diff options
Diffstat (limited to 'src/core')
72 files changed, 1012 insertions, 362 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 7cb86ed92..6d5b5a2d0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -185,7 +185,7 @@ struct System::Impl { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); return ResultStatus::ErrorGetLoader; } - std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = + std::pair<std::optional<u32>, Loader::ResultStatus> system_mode = app_loader->LoadKernelSystemMode(); if (system_mode.second != Loader::ResultStatus::Success) { @@ -312,6 +312,10 @@ Cpu& System::CurrentCpuCore() { return impl->CurrentCpuCore(); } +const Cpu& System::CurrentCpuCore() const { + return impl->CurrentCpuCore(); +} + System::ResultStatus System::RunLoop(bool tight_loop) { return impl->RunLoop(tight_loop); } @@ -342,7 +346,11 @@ PerfStatsResults System::GetAndResetPerfStats() { return impl->GetAndResetPerfStats(); } -Core::TelemetrySession& System::TelemetrySession() const { +TelemetrySession& System::TelemetrySession() { + return *impl->telemetry_session; +} + +const TelemetrySession& System::TelemetrySession() const { return *impl->telemetry_session; } @@ -350,7 +358,11 @@ ARM_Interface& System::CurrentArmInterface() { return CurrentCpuCore().ArmInterface(); } -std::size_t System::CurrentCoreIndex() { +const ARM_Interface& System::CurrentArmInterface() const { + return CurrentCpuCore().ArmInterface(); +} + +std::size_t System::CurrentCoreIndex() const { return CurrentCpuCore().CoreIndex(); } @@ -358,6 +370,10 @@ Kernel::Scheduler& System::CurrentScheduler() { return CurrentCpuCore().Scheduler(); } +const Kernel::Scheduler& System::CurrentScheduler() const { + return CurrentCpuCore().Scheduler(); +} + Kernel::Scheduler& System::Scheduler(std::size_t core_index) { return CpuCore(core_index).Scheduler(); } @@ -378,6 +394,10 @@ ARM_Interface& System::ArmInterface(std::size_t core_index) { return CpuCore(core_index).ArmInterface(); } +const ARM_Interface& System::ArmInterface(std::size_t core_index) const { + return CpuCore(core_index).ArmInterface(); +} + Cpu& System::CpuCore(std::size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); return *impl->cpu_cores[core_index]; @@ -392,6 +412,10 @@ ExclusiveMonitor& System::Monitor() { return *impl->cpu_exclusive_monitor; } +const ExclusiveMonitor& System::Monitor() const { + return *impl->cpu_exclusive_monitor; +} + Tegra::GPU& System::GPU() { return *impl->gpu_core; } diff --git a/src/core/core.h b/src/core/core.h index 173be45f8..cfacceb81 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -129,11 +129,11 @@ public: */ bool IsPoweredOn() const; - /** - * Returns a reference to the telemetry session for this emulation session. - * @returns Reference to the telemetry session. - */ - Core::TelemetrySession& TelemetrySession() const; + /// Gets a reference to the telemetry session for this emulation session. + Core::TelemetrySession& TelemetrySession(); + + /// Gets a reference to the telemetry session for this emulation session. + const Core::TelemetrySession& TelemetrySession() const; /// Prepare the core emulation for a reschedule void PrepareReschedule(); @@ -144,24 +144,36 @@ public: /// Gets an ARM interface to the CPU core that is currently running ARM_Interface& CurrentArmInterface(); + /// Gets an ARM interface to the CPU core that is currently running + const ARM_Interface& CurrentArmInterface() const; + /// Gets the index of the currently running CPU core - std::size_t CurrentCoreIndex(); + std::size_t CurrentCoreIndex() const; /// Gets the scheduler for the CPU core that is currently running Kernel::Scheduler& CurrentScheduler(); - /// Gets an ARM interface to the CPU core with the specified index + /// Gets the scheduler for the CPU core that is currently running + const Kernel::Scheduler& CurrentScheduler() const; + + /// Gets a reference to an ARM interface for the CPU core with the specified index ARM_Interface& ArmInterface(std::size_t core_index); + /// Gets a const reference to an ARM interface from the CPU core with the specified index + const ARM_Interface& ArmInterface(std::size_t core_index) const; + /// Gets a CPU interface to the CPU core with the specified index Cpu& CpuCore(std::size_t core_index); /// Gets a CPU interface to the CPU core with the specified index const Cpu& CpuCore(std::size_t core_index) const; - /// Gets the exclusive monitor + /// Gets a reference to the exclusive monitor ExclusiveMonitor& Monitor(); + /// Gets a constant reference to the exclusive monitor + const ExclusiveMonitor& Monitor() const; + /// Gets a mutable reference to the GPU interface Tegra::GPU& GPU(); @@ -230,6 +242,9 @@ private: /// Returns the currently running CPU core Cpu& CurrentCpuCore(); + /// Returns the currently running CPU core + const Cpu& CurrentCpuCore() const; + /** * Initialize the emulated system. * @param emu_window Reference to the host-system window used for video output and keyboard diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 89ae79eb3..904afa039 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -141,28 +141,28 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) return mac_key; } -boost::optional<Key128> DeriveSDSeed() { +std::optional<Key128> DeriveSDSeed() { const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000043", "rb+"); if (!save_43.IsOpen()) - return boost::none; + return {}; const FileUtil::IOFile sd_private( FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); if (!sd_private.IsOpen()) - return boost::none; + return {}; std::array<u8, 0x10> private_seed{}; if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { - return boost::none; + return {}; } std::array<u8, 0x10> buffer{}; std::size_t offset = 0; for (; offset + 0x10 < save_43.GetSize(); ++offset) { if (!save_43.Seek(offset, SEEK_SET)) { - return boost::none; + return {}; } save_43.ReadBytes(buffer.data(), buffer.size()); @@ -172,12 +172,12 @@ boost::optional<Key128> DeriveSDSeed() { } if (!save_43.Seek(offset + 0x10, SEEK_SET)) { - return boost::none; + return {}; } Key128 seed{}; if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { - return boost::none; + return {}; } return seed; } @@ -291,26 +291,26 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) { } template <size_t size> -static boost::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { +static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { u64 offset = 0; for (size_t i = 0x20; i < data.size() - 0x10; ++i) { if (data[i] == 0x1) { offset = i + 1; break; } else if (data[i] != 0x0) { - return boost::none; + return {}; } } return offset; } -boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, - const RSAKeyPair<2048>& key) { +std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, + const RSAKeyPair<2048>& key) { u32 cert_authority; std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); if (cert_authority == 0) - return boost::none; + return {}; if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority {:08X}.", @@ -321,7 +321,7 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); if (rights_id == Key128{}) - return boost::none; + return {}; Key128 key_temp{}; @@ -356,17 +356,17 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size()); if (m_0 != 0) - return boost::none; + return {}; m_1 = m_1 ^ MGF1<0x20>(m_2); m_2 = m_2 ^ MGF1<0xDF>(m_1); const auto offset = FindTicketOffset(m_2); - if (offset == boost::none) - return boost::none; - ASSERT(offset.get() > 0); + if (!offset) + return {}; + ASSERT(*offset > 0); - std::memcpy(key_temp.data(), m_2.data() + offset.get(), key_temp.size()); + std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size()); return std::make_pair(rights_id, key_temp); } @@ -661,8 +661,8 @@ void KeyManager::DeriveSDSeedLazy() { return; const auto res = DeriveSDSeed(); - if (res != boost::none) - SetKey(S128KeyType::SDSeed, res.get()); + if (res) + SetKey(S128KeyType::SDSeed, *res); } static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) { @@ -889,9 +889,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { for (const auto& raw : res) { const auto pair = ParseTicket(raw, rsa_key); - if (pair == boost::none) + if (!pair) continue; - const auto& [rid, key] = pair.value(); + const auto& [rid, key] = *pair; u128 rights_id; std::memcpy(rights_id.data(), rid.data(), rid.size()); SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index cccb3c0ae..22f268c65 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -6,9 +6,10 @@ #include <array> #include <map> +#include <optional> #include <string> + #include <boost/container/flat_map.hpp> -#include <boost/optional.hpp> #include <fmt/format.h> #include "common/common_types.h" #include "core/crypto/partition_data_manager.h" @@ -191,14 +192,14 @@ Key128 DeriveMasterKey(const std::array<u8, 0x90>& keyblob, const Key128& master std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblob, const Key128& key); -boost::optional<Key128> DeriveSDSeed(); +std::optional<Key128> DeriveSDSeed(); Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys); std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save); // Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset // 0x140-0x144 is zero) -boost::optional<std::pair<Key128, Key128>> ParseTicket( - const TicketRaw& ticket, const RSAKeyPair<2048>& eticket_extended_key); +std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, + const RSAKeyPair<2048>& eticket_extended_key); } // namespace Core::Crypto diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 77e04704e..b46fe893c 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -4,10 +4,9 @@ #include <algorithm> #include <cstring> +#include <optional> #include <utility> -#include <boost/optional.hpp> - #include "common/logging/log.h" #include "core/crypto/aes_util.h" #include "core/crypto/ctr_encryption_layer.h" @@ -306,18 +305,18 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low}); subsection_buckets.back().entries.push_back({size, {0}, 0}); - boost::optional<Core::Crypto::Key128> key = boost::none; + std::optional<Core::Crypto::Key128> key = {}; if (encrypted) { if (has_rights_id) { status = Loader::ResultStatus::Success; key = GetTitlekey(); - if (key == boost::none) { + if (!key) { status = Loader::ResultStatus::ErrorMissingTitlekey; return false; } } else { key = GetKeyAreaKey(NCASectionCryptoType::BKTR); - if (key == boost::none) { + if (!key) { status = Loader::ResultStatus::ErrorMissingKeyAreaKey; return false; } @@ -332,7 +331,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl auto bktr = std::make_shared<BKTR>( bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), relocation_block, relocation_buckets, subsection_block, subsection_buckets, encrypted, - encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset, + encrypted ? *key : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset, section.raw.section_ctr); // BKTR applies to entire IVFC, so make an offset version to level 6 @@ -388,11 +387,11 @@ u8 NCA::GetCryptoRevision() const { return master_key_id; } -boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { +std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { const auto master_key_id = GetCryptoRevision(); if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) - return boost::none; + return {}; std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( @@ -416,25 +415,25 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty return out; } -boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() { +std::optional<Core::Crypto::Key128> NCA::GetTitlekey() { const auto master_key_id = GetCryptoRevision(); u128 rights_id{}; memcpy(rights_id.data(), header.rights_id.data(), 16); if (rights_id == u128{}) { status = Loader::ResultStatus::ErrorInvalidRightsID; - return boost::none; + return {}; } auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); if (titlekey == Core::Crypto::Key128{}) { status = Loader::ResultStatus::ErrorMissingTitlekey; - return boost::none; + return {}; } if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) { status = Loader::ResultStatus::ErrorMissingTitlekek; - return boost::none; + return {}; } Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( @@ -458,25 +457,25 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s case NCASectionCryptoType::BKTR: LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); { - boost::optional<Core::Crypto::Key128> key = boost::none; + std::optional<Core::Crypto::Key128> key = {}; if (has_rights_id) { status = Loader::ResultStatus::Success; key = GetTitlekey(); - if (key == boost::none) { + if (!key) { if (status == Loader::ResultStatus::Success) status = Loader::ResultStatus::ErrorMissingTitlekey; return nullptr; } } else { key = GetKeyAreaKey(NCASectionCryptoType::CTR); - if (key == boost::none) { + if (!key) { status = Loader::ResultStatus::ErrorMissingKeyAreaKey; return nullptr; } } - auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( - std::move(in), key.value(), starting_offset); + auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key, + starting_offset); std::vector<u8> iv(16); for (u8 i = 0; i < 8; ++i) iv[i] = s_header.raw.section_ctr[0x8 - i - 1]; diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 211946686..4bba55607 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -6,9 +6,10 @@ #include <array> #include <memory> +#include <optional> #include <string> #include <vector> -#include <boost/optional.hpp> + #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" @@ -111,8 +112,8 @@ private: bool ReadPFS0Section(const NCASectionHeader& section, const NCASectionTableEntry& entry); u8 GetCryptoRevision() const; - boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; - boost::optional<Core::Crypto::Key128> GetTitlekey(); + std::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; + std::optional<Core::Crypto::Key128> GetTitlekey(); VirtualFile Decrypt(const NCASectionHeader& header, VirtualFile in, u64 starting_offset); std::vector<VirtualDir> dirs; diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index a012c2be9..c8fa912bf 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -66,4 +66,10 @@ std::string NACP::GetVersionString() const { return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), raw->version_string.size()); } + +std::vector<u8> NACP::GetRawBytes() const { + std::vector<u8> out(sizeof(RawNACP)); + std::memcpy(out.data(), raw.get(), sizeof(RawNACP)); + return out; +} } // namespace FileSys diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 141f7e056..bfaad46b4 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -81,6 +81,7 @@ public: u64 GetTitleId() const; u64 GetDLCBaseTitleId() const; std::string GetVersionString() const; + std::vector<u8> GetRawBytes() const; private: std::unique_ptr<RawNACP> raw; diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h index 3d377b0af..a62502193 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.h +++ b/src/core/file_sys/fsmitm_romfsbuild.h @@ -27,7 +27,6 @@ #include <map> #include <memory> #include <string> -#include <boost/detail/container_fwd.hpp> #include "common/common_types.h" #include "core/file_sys/vfs.h" diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 999939d5a..485c4913a 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp @@ -103,12 +103,12 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { offset += sizeof(u16); const auto data = ips->ReadByte(offset++); - if (data == boost::none) + if (!data) return nullptr; if (real_offset + rle_size > in_data.size()) rle_size = static_cast<u16>(in_data.size() - real_offset); - std::memset(in_data.data() + real_offset, data.get(), rle_size); + std::memset(in_data.data() + real_offset, *data, rle_size); } else { // Standard Patch auto read = data_size; if (real_offset + read > in_data.size()) diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 3a1623ca0..8d062eb3e 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -66,7 +66,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { if (update != nullptr && update->GetExeFS() != nullptr && update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", - FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); + FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); exefs = update->GetExeFS(); } @@ -249,7 +249,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content if (new_nca->GetStatus() == Loader::ResultStatus::Success && new_nca->GetRomFS() != nullptr) { LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", - FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); + FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); romfs = new_nca->GetRomFS(); } } else if (update_raw != nullptr) { @@ -293,12 +293,11 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam } else { if (installed->HasEntry(update_tid, ContentRecordType::Program)) { const auto meta_ver = installed->GetEntryVersion(update_tid); - if (meta_ver == boost::none || meta_ver.get() == 0) { + if (meta_ver.value_or(0) == 0) { out.insert_or_assign("Update", ""); } else { out.insert_or_assign( - "Update", - FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements)); + "Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements)); } } else if (update_raw != nullptr) { out.insert_or_assign("Update", "PACKED"); diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 29b100414..96302a241 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -159,28 +159,28 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { return file; } -static boost::optional<NcaID> CheckMapForContentRecord( +static std::optional<NcaID> CheckMapForContentRecord( const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) { if (map.find(title_id) == map.end()) - return boost::none; + return {}; const auto& cnmt = map.at(title_id); const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(), [type](const ContentRecord& rec) { return rec.type == type; }); if (iter == cnmt.GetContentRecords().end()) - return boost::none; + return {}; - return boost::make_optional(iter->nca_id); + return std::make_optional(iter->nca_id); } -boost::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id, - ContentRecordType type) const { +std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id, + ContentRecordType type) const { if (type == ContentRecordType::Meta && meta_id.find(title_id) != meta_id.end()) return meta_id.at(title_id); const auto res1 = CheckMapForContentRecord(yuzu_meta, title_id, type); - if (res1 != boost::none) + if (res1) return res1; return CheckMapForContentRecord(meta, title_id, type); } @@ -283,17 +283,14 @@ bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const { VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const { const auto id = GetNcaIDFromMetadata(title_id, type); - if (id == boost::none) - return nullptr; - - return GetFileAtID(id.get()); + return id ? GetFileAtID(*id) : nullptr; } VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const { return GetEntryUnparsed(entry.title_id, entry.type); } -boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { +std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { const auto meta_iter = meta.find(title_id); if (meta_iter != meta.end()) return meta_iter->second.GetTitleVersion(); @@ -302,15 +299,12 @@ boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { if (yuzu_meta_iter != yuzu_meta.end()) return yuzu_meta_iter->second.GetTitleVersion(); - return boost::none; + return {}; } VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const { const auto id = GetNcaIDFromMetadata(title_id, type); - if (id == boost::none) - return nullptr; - - return parser(GetFileAtID(id.get()), id.get()); + return id ? parser(GetFileAtID(*id), *id) : nullptr; } VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const { @@ -364,8 +358,8 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const { } std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( - boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type, - boost::optional<u64> title_id) const { + std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, + std::optional<u64> title_id) const { std::vector<RegisteredCacheEntry> out; IterateAllMetadata<RegisteredCacheEntry>( out, @@ -373,11 +367,11 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( return RegisteredCacheEntry{c.GetTitleID(), r.type}; }, [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) { - if (title_type != boost::none && title_type.get() != c.GetType()) + if (title_type && *title_type != c.GetType()) return false; - if (record_type != boost::none && record_type.get() != r.type) + if (record_type && *record_type != r.type) return false; - if (title_id != boost::none && title_id.get() != c.GetTitleID()) + if (title_id && *title_id != c.GetTitleID()) return false; return true; }); @@ -459,7 +453,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, bool overwrite_if_exists, - boost::optional<NcaID> override_id) { + std::optional<NcaID> override_id) { const auto in = nca->GetBaseFile(); Core::Crypto::SHA256Hash hash{}; @@ -468,12 +462,12 @@ InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const Vfs // game is massive), we're going to cheat and only hash the first MB of the NCA. // Also, for XCIs the NcaID matters, so if the override id isn't none, use that. NcaID id{}; - if (override_id == boost::none) { + if (override_id) { + id = *override_id; + } else { const auto& data = in->ReadBytes(0x100000); mbedtls_sha256(data.data(), data.size(), hash.data(), 0); memcpy(id.data(), hash.data(), 16); - } else { - id = override_id.get(); } std::string path = GetRelativePathFromNcaID(id, false, true); @@ -543,14 +537,14 @@ bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const { return HasEntry(entry.title_id, entry.type); } -boost::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const { +std::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const { for (const auto& c : caches) { const auto res = c->GetEntryVersion(title_id); - if (res != boost::none) + if (res) return res; } - return boost::none; + return {}; } VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const { @@ -609,8 +603,8 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const { } std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter( - boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type, - boost::optional<u64> title_id) const { + std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, + std::optional<u64> title_id) const { std::vector<RegisteredCacheEntry> out; for (const auto& c : caches) { c->IterateAllMetadata<RegisteredCacheEntry>( @@ -619,11 +613,11 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter( return RegisteredCacheEntry{c.GetTitleID(), r.type}; }, [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) { - if (title_type != boost::none && title_type.get() != c.GetType()) + if (title_type && *title_type != c.GetType()) return false; - if (record_type != boost::none && record_type.get() != r.type) + if (record_type && *record_type != r.type) return false; - if (title_id != boost::none && title_id.get() != c.GetTitleID()) + if (title_id && *title_id != c.GetTitleID()) return false; return true; }); diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 5beceffb3..6cfb16017 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -84,7 +84,7 @@ public: bool HasEntry(u64 title_id, ContentRecordType type) const; bool HasEntry(RegisteredCacheEntry entry) const; - boost::optional<u32> GetEntryVersion(u64 title_id) const; + std::optional<u32> GetEntryVersion(u64 title_id) const; VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; @@ -96,11 +96,10 @@ public: std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; std::vector<RegisteredCacheEntry> ListEntries() const; - // If a parameter is not boost::none, it will be filtered for from all entries. + // If a parameter is not std::nullopt, it will be filtered for from all entries. std::vector<RegisteredCacheEntry> ListEntriesFilter( - boost::optional<TitleType> title_type = boost::none, - boost::optional<ContentRecordType> record_type = boost::none, - boost::optional<u64> title_id = boost::none) const; + std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, + std::optional<u64> title_id = {}) const; // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure // there is a meta NCA and all of them are accessible. @@ -125,12 +124,11 @@ private: std::vector<NcaID> AccumulateFiles() const; void ProcessFiles(const std::vector<NcaID>& ids); void AccumulateYuzuMeta(); - boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; + std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; VirtualFile GetFileAtID(NcaID id) const; VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, - bool overwrite_if_exists, - boost::optional<NcaID> override_id = boost::none); + bool overwrite_if_exists, std::optional<NcaID> override_id = {}); bool RawInstallYuzuMeta(const CNMT& cnmt); VirtualDir dir; @@ -153,7 +151,7 @@ public: bool HasEntry(u64 title_id, ContentRecordType type) const; bool HasEntry(RegisteredCacheEntry entry) const; - boost::optional<u32> GetEntryVersion(u64 title_id) const; + std::optional<u32> GetEntryVersion(u64 title_id) const; VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; @@ -165,11 +163,10 @@ public: std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; std::vector<RegisteredCacheEntry> ListEntries() const; - // If a parameter is not boost::none, it will be filtered for from all entries. + // If a parameter is not std::nullopt, it will be filtered for from all entries. std::vector<RegisteredCacheEntry> ListEntriesFilter( - boost::optional<TitleType> title_type = boost::none, - boost::optional<ContentRecordType> record_type = boost::none, - boost::optional<u64> title_id = boost::none) const; + std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, + std::optional<u64> title_id = {}) const; private: std::vector<RegisteredCache*> caches; diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index ef1aaebbb..5434f2149 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr return MakeResult<VirtualDir>(std::move(out)); } -std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, - u128 user_id, u64 save_id) { - // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should - // be interpreted as the title id of the current process. - if (type == SaveDataType::SaveData && title_id == 0) - title_id = Core::CurrentProcess()->GetTitleID(); - - std::string out; +VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const { + return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space)); +} +std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { switch (space) { case SaveDataSpaceId::NandSystem: - out = "/system/"; - break; + return "/system/"; case SaveDataSpaceId::NandUser: - out = "/user/"; - break; + return "/user/"; case SaveDataSpaceId::TemporaryStorage: - out = "/temp/"; - break; + return "/temp/"; default: ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); + return "/unrecognized/"; ///< To prevent corruption when ignoring asserts. } +} + +std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, + u128 user_id, u64 save_id) { + // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should + // be interpreted as the title id of the current process. + if (type == SaveDataType::SaveData && title_id == 0) + title_id = Core::CurrentProcess()->GetTitleID(); + + std::string out = GetSaveDataSpaceIdPath(space); switch (type) { case SaveDataType::SystemSaveData: diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index d69ef6741..2a0088040 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -52,6 +52,9 @@ public: ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); + VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; + + static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id); diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 3824c74e0..7b584de7f 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -167,13 +167,13 @@ std::string VfsFile::GetExtension() const { VfsDirectory::~VfsDirectory() = default; -boost::optional<u8> VfsFile::ReadByte(std::size_t offset) const { +std::optional<u8> VfsFile::ReadByte(std::size_t offset) const { u8 out{}; std::size_t size = Read(&out, 1, offset); if (size == 1) return out; - return boost::none; + return {}; } std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const { diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 09dc9f288..002f99d4e 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -4,13 +4,15 @@ #pragma once +#include <functional> #include <map> #include <memory> +#include <optional> #include <string> #include <string_view> #include <type_traits> #include <vector> -#include <boost/optional.hpp> + #include "common/common_types.h" #include "core/file_sys/vfs_types.h" @@ -103,8 +105,8 @@ public: // into file. Returns number of bytes successfully written. virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0; - // Reads exactly one byte at the offset provided, returning boost::none on error. - virtual boost::optional<u8> ReadByte(std::size_t offset = 0) const; + // Reads exactly one byte at the offset provided, returning std::nullopt on error. + virtual std::optional<u8> ReadByte(std::size_t offset = 0) const; // Reads size bytes starting at offset in file into a vector. virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const; // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(), diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index a4c6719a0..c96f88488 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -57,11 +57,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t return file->Write(data, TrimToFit(length, r_offset), offset + r_offset); } -boost::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { +std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { if (r_offset < size) return file->ReadByte(offset + r_offset); - return boost::none; + return {}; } std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const { diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 8062702a7..f7b7a3256 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -29,7 +29,7 @@ public: bool IsReadable() const override; std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; - boost::optional<u8> ReadByte(std::size_t offset) const override; + std::optional<u8> ReadByte(std::size_t offset) const override; std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override; std::vector<u8> ReadAllBytes() const override; bool WriteByte(u8 data, std::size_t offset) override; diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 44fab51d1..9f5a90b1b 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h @@ -53,10 +53,10 @@ public: return 0; } - boost::optional<u8> ReadByte(std::size_t offset) const override { + std::optional<u8> ReadByte(std::size_t offset) const override { if (offset < size) return value; - return boost::none; + return {}; } std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index a4bfe2eb0..0a7142ada 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -117,8 +117,7 @@ public: AlignWithPadding(); - const bool request_has_domain_header{context.GetDomainMessageHeader() != nullptr}; - if (context.Session()->IsDomain() && request_has_domain_header) { + if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) { IPC::DomainMessageHeader domain_header{}; domain_header.num_objects = num_domain_objects; PushRaw(domain_header); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index f01491daa..a38e34b74 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -161,8 +161,12 @@ public: return buffer_c_desciptors; } - const std::shared_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { - return domain_message_header; + const IPC::DomainMessageHeader* GetDomainMessageHeader() const { + return domain_message_header.get(); + } + + bool HasDomainMessageHeader() const { + return domain_message_header != nullptr; } /// Helper function to read a buffer using the appropriate buffer descriptor diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4b6b32dd5..1fd4ba5d2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -32,7 +32,7 @@ namespace Kernel { */ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) { const auto proper_handle = static_cast<Handle>(thread_handle); - auto& system = Core::System::GetInstance(); + const auto& system = Core::System::GetInstance(); // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); @@ -90,7 +90,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_ /// The timer callback event, called when a timer is fired static void TimerCallback(u64 timer_handle, int cycles_late) { const auto proper_handle = static_cast<Handle>(timer_handle); - auto& system = Core::System::GetInstance(); + const auto& system = Core::System::GetInstance(); SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle); if (timer == nullptr) { diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index dd541ffcc..0743670ad 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -6,8 +6,6 @@ #include <utility> #include <vector> -#include <boost/range/algorithm_ext/erase.hpp> - #include "common/assert.h" #include "core/core.h" #include "core/hle/kernel/errors.h" diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 420218d59..f06b6bb55 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -5,11 +5,9 @@ #include <algorithm> #include <memory> #include "common/assert.h" -#include "common/common_funcs.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" @@ -17,6 +15,7 @@ #include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" +#include "core/settings.h" namespace Kernel { @@ -35,6 +34,11 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { process->process_id = kernel.CreateNewProcessID(); process->svc_access_mask.set(); + std::mt19937 rng(Settings::values.rng_seed.value_or(0)); + std::uniform_int_distribution<u64> distribution; + std::generate(process->random_entropy.begin(), process->random_entropy.end(), + [&] { return distribution(rng); }); + kernel.AppendNewProcess(process); return process; } @@ -241,83 +245,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { } ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { - if (target < vm_manager.GetHeapRegionBaseAddress() || - target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { - return ERR_INVALID_ADDRESS; - } - - if (heap_memory == nullptr) { - // Initialize heap - heap_memory = std::make_shared<std::vector<u8>>(); - heap_start = heap_end = target; - } else { - vm_manager.UnmapRange(heap_start, heap_end - heap_start); - } - - // If necessary, expand backing vector to cover new heap extents. - if (target < heap_start) { - heap_memory->insert(begin(*heap_memory), heap_start - target, 0); - heap_start = target; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); - } - if (target + size > heap_end) { - heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); - heap_end = target + size; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); - } - ASSERT(heap_end - heap_start == heap_memory->size()); - - CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, - size, MemoryState::Heap)); - vm_manager.Reprotect(vma, perms); - - heap_used = size; - - return MakeResult<VAddr>(heap_end - size); + return vm_manager.HeapAllocate(target, size, perms); } ResultCode Process::HeapFree(VAddr target, u32 size) { - if (target < vm_manager.GetHeapRegionBaseAddress() || - target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { - return ERR_INVALID_ADDRESS; - } - - if (size == 0) { - return RESULT_SUCCESS; - } - - ResultCode result = vm_manager.UnmapRange(target, size); - if (result.IsError()) - return result; - - heap_used -= size; - - return RESULT_SUCCESS; + return vm_manager.HeapFree(target, size); } ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { - auto vma = vm_manager.FindVMA(src_addr); - - ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); - ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); - - // The returned VMA might be a bigger one encompassing the desired address. - auto vma_offset = src_addr - vma->first; - ASSERT_MSG(vma_offset + size <= vma->second.size, - "Shared memory exceeds bounds of mapped block"); - - const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; - std::size_t backing_block_offset = vma->second.offset + vma_offset; - - CASCADE_RESULT(auto new_vma, - vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, - MemoryState::Mapped)); - // Protect mirror with permissions from old region - vm_manager.Reprotect(new_vma, vma->second.permissions); - // Remove permissions from old region - vm_manager.Reprotect(vma, VMAPermission::None); - - return RESULT_SUCCESS; + return vm_manager.MirrorMemory(dst_addr, src_addr, size); } ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 8d2616c79..cf48787ce 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -8,6 +8,7 @@ #include <bitset> #include <cstddef> #include <memory> +#include <random> #include <string> #include <vector> #include <boost/container/static_vector.hpp> @@ -119,6 +120,8 @@ struct CodeSet final { class Process final : public Object { public: + static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; + static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); std::string GetTypeName() const override { @@ -212,6 +215,11 @@ public: total_process_running_time_ticks += ticks; } + /// Gets 8 bytes of random data for svcGetInfo RandomEntropy + u64 GetRandomEntropy(std::size_t index) const { + return random_entropy.at(index); + } + /** * Loads process-specifics configuration info with metadata provided * by an executable. @@ -292,17 +300,6 @@ private: u32 allowed_thread_priority_mask = 0xFFFFFFFF; u32 is_virtual_address_memory_enabled = 0; - // Memory used to back the allocations in the regular heap. A single vector is used to cover - // the entire virtual address space extents that bound the allocations, including any holes. - // This makes deallocation and reallocation of holes fast and keeps process memory contiguous - // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. - std::shared_ptr<std::vector<u8>> heap_memory; - - // The left/right bounds of the address space covered by heap_memory. - VAddr heap_start = 0; - VAddr heap_end = 0; - u64 heap_used = 0; - /// The Thread Local Storage area is allocated as processes create threads, /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part /// holds the TLS for a specific thread. This vector contains which parts are in use for each @@ -321,6 +318,9 @@ private: /// Per-process handle table for storing created object handles in. HandleTable handle_table; + /// Random values for svcGetInfo RandomEntropy + std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; + std::string name; }; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 5fc320403..80897f3a4 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -63,7 +63,7 @@ void ServerSession::Acquire(Thread* thread) { } ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { - auto& domain_message_header = context.GetDomainMessageHeader(); + auto* const domain_message_header = context.GetDomainMessageHeader(); if (domain_message_header) { // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs context.SetDomainRequestHandlers(domain_request_handlers); @@ -111,7 +111,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { ResultCode result = RESULT_SUCCESS; // If the session has been converted to a domain, handle the domain request - if (IsDomain() && context.GetDomainMessageHeader()) { + if (IsDomain() && context.HasDomainMessageHeader()) { result = HandleDomainSyncRequest(context); // If there is no domain header, the regular session handler is used } else if (hle_handler != nullptr) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4e490e2b5..b0b6508d9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -34,6 +34,7 @@ #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" +#include "core/settings.h" namespace Kernel { namespace { @@ -395,16 +396,42 @@ struct BreakReason { /// Break program execution static void Break(u32 reason, u64 info1, u64 info2) { BreakReason break_reason{reason}; + bool has_dumped_buffer{}; + const auto handle_debug_buffer = [&](VAddr addr, u64 sz) { + if (sz == 0 || addr == 0 || has_dumped_buffer) { + return; + } + + // This typically is an error code so we're going to assume this is the case + if (sz == sizeof(u32)) { + LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); + } else { + // We don't know what's in here so we'll hexdump it + std::vector<u8> debug_buffer(sz); + Memory::ReadBlock(addr, debug_buffer.data(), sz); + std::string hexdump; + for (std::size_t i = 0; i < debug_buffer.size(); i++) { + hexdump += fmt::format("{:02X} ", debug_buffer[i]); + if (i != 0 && i % 16 == 0) { + hexdump += '\n'; + } + } + LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump); + } + has_dumped_buffer = true; + }; switch (break_reason.break_type) { case BreakType::Panic: LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}", info1, info2); + handle_debug_buffer(info1, info2); break; case BreakType::AssertionFailed: LOG_CRITICAL(Debug_Emulated, "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}", info1, info2); + handle_debug_buffer(info1, info2); break; case BreakType::PreNROLoad: LOG_WARNING( @@ -433,6 +460,7 @@ static void Break(u32 reason, u64 info1, u64 info2) { Debug_Emulated, "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}", static_cast<u32>(break_reason.break_type.Value()), info1, info2); + handle_debug_buffer(info1, info2); break; } @@ -441,6 +469,7 @@ static void Break(u32 reason, u64 info1, u64 info2) { Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); + handle_debug_buffer(info1, info2); ASSERT(false); Core::CurrentProcess()->PrepareForTermination(); @@ -530,7 +559,16 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = 0; break; case GetInfoType::RandomEntropy: - *result = 0; + if (handle != 0) { + return ERR_INVALID_HANDLE; + } + + if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { + return ERR_INVALID_COMBINATION_KERNEL; + } + + *result = current_process->GetRandomEntropy(info_sub_id); + return RESULT_SUCCESS; break; case GetInfoType::ASLRRegionBaseAddr: *result = vm_manager.GetASLRRegionBaseAddress(); @@ -572,7 +610,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) return ERR_INVALID_HANDLE; } - auto& system = Core::System::GetInstance(); + const auto& system = Core::System::GetInstance(); const auto& scheduler = system.CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); const bool same_thread = current_thread == thread; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 59bc9e0af..dd5cd9ced 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -4,9 +4,9 @@ #include <algorithm> #include <cinttypes> +#include <optional> #include <vector> -#include <boost/optional.hpp> #include <boost/range/algorithm_ext/erase.hpp> #include "common/assert.h" @@ -94,7 +94,7 @@ void Thread::CancelWakeupTimer() { CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle); } -static boost::optional<s32> GetNextProcessorId(u64 mask) { +static std::optional<s32> GetNextProcessorId(u64 mask) { for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { if (mask & (1ULL << index)) { if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) { @@ -142,7 +142,7 @@ void Thread::ResumeFromWait() { status = ThreadStatus::Ready; - boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); + std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); if (!new_processor_id) { new_processor_id = processor_id; } @@ -369,7 +369,7 @@ void Thread::ChangeCore(u32 core, u64 mask) { return; } - boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; + std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; if (!new_processor_id) { new_processor_id = processor_id; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 1a92c8f70..ec7fd6150 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p return RESULT_SUCCESS; } +ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { + if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || + target + size < target) { + return ERR_INVALID_ADDRESS; + } + + if (heap_memory == nullptr) { + // Initialize heap + heap_memory = std::make_shared<std::vector<u8>>(); + heap_start = heap_end = target; + } else { + UnmapRange(heap_start, heap_end - heap_start); + } + + // If necessary, expand backing vector to cover new heap extents. + if (target < heap_start) { + heap_memory->insert(begin(*heap_memory), heap_start - target, 0); + heap_start = target; + RefreshMemoryBlockMappings(heap_memory.get()); + } + if (target + size > heap_end) { + heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); + heap_end = target + size; + RefreshMemoryBlockMappings(heap_memory.get()); + } + ASSERT(heap_end - heap_start == heap_memory->size()); + + CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size, + MemoryState::Heap)); + Reprotect(vma, perms); + + heap_used = size; + + return MakeResult<VAddr>(heap_end - size); +} + +ResultCode VMManager::HeapFree(VAddr target, u64 size) { + if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || + target + size < target) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0) { + return RESULT_SUCCESS; + } + + const ResultCode result = UnmapRange(target, size); + if (result.IsError()) { + return result; + } + + heap_used -= size; + return RESULT_SUCCESS; +} + +ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { + const auto vma = FindVMA(src_addr); + + ASSERT_MSG(vma != vma_map.end(), "Invalid memory address"); + ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); + + // The returned VMA might be a bigger one encompassing the desired address. + const auto vma_offset = src_addr - vma->first; + ASSERT_MSG(vma_offset + size <= vma->second.size, + "Shared memory exceeds bounds of mapped block"); + + const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; + const std::size_t backing_block_offset = vma->second.offset + vma_offset; + + CASCADE_RESULT(auto new_vma, MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, + MemoryState::Mapped)); + // Protect mirror with permissions from old region + Reprotect(new_vma, vma->second.permissions); + // Remove permissions from old region + Reprotect(vma, VMAPermission::None); + + return RESULT_SUCCESS; +} + void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { // If this ever proves to have a noticeable performance impact, allow users of the function to // specify a specific range of addresses to limit the scan to. @@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const { } u64 VMManager::GetTotalHeapUsage() const { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x0; + return heap_used; } VAddr VMManager::GetAddressSpaceBaseAddress() const { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 2447cbb8f..248cc46dc 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -186,6 +186,11 @@ public: /// Changes the permissions of a range of addresses, splitting VMAs as necessary. ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); + ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); + ResultCode HeapFree(VAddr target, u64 size); + + ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); + /** * Scans all VMAs and updates the page table range of any that use the given vector as backing * memory. This should be called after any operation that causes reallocation of the vector. @@ -343,5 +348,15 @@ private: VAddr tls_io_region_base = 0; VAddr tls_io_region_end = 0; + + // Memory used to back the allocations in the regular heap. A single vector is used to cover + // the entire virtual address space extents that bound the allocations, including any holes. + // This makes deallocation and reallocation of holes fast and keeps process memory contiguous + // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. + std::shared_ptr<std::vector<u8>> heap_memory; + // The left/right bounds of the address space covered by heap_memory. + VAddr heap_start = 0; + VAddr heap_end = 0; + u64 heap_used = 0; }; } // namespace Kernel diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index c6437a671..c629f9357 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -242,6 +242,30 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo LOG_DEBUG(Service_ACC, "called"); } +void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ACC, "called"); + // A u8 is passed into this function which we can safely ignore. It's to determine if we have + // access to use the network or not by the looks of it + IPC::ResponseBuilder rb{ctx, 6}; + if (profile_manager->GetUserCount() != 1) { + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u128>(INVALID_UUID); + return; + } + + const auto user_list = profile_manager->GetAllUsers(); + if (std::all_of(user_list.begin(), user_list.end(), + [](const auto& user) { return user.uuid == INVALID_UUID; })) { + rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code + rb.PushRaw<u128>(INVALID_UUID); + return; + } + + // Select the first user we have + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid); +} + Module::Interface::Interface(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, const char* name) : ServiceFramework(name), module(std::move(module)), diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index c7ed74351..89b2104fa 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -27,6 +27,7 @@ public: void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx); + void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> module; diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index ad455c3a7..5e2030355 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -17,7 +17,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {5, &ACC_SU::GetProfile, "GetProfile"}, {6, nullptr, "GetProfileDigest"}, {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, - {51, nullptr, "TrySelectUserWithoutInteraction"}, + {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, {60, nullptr, "ListOpenContextStoredUsers"}, {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 72d4adf35..a4d705b45 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -17,7 +17,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {5, &ACC_U0::GetProfile, "GetProfile"}, {6, nullptr, "GetProfileDigest"}, {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, - {51, nullptr, "TrySelectUserWithoutInteraction"}, + {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, {60, nullptr, "ListOpenContextStoredUsers"}, {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index d480f08e5..8fffc93b5 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -17,7 +17,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {5, &ACC_U1::GetProfile, "GetProfile"}, {6, nullptr, "GetProfileDigest"}, {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, - {51, nullptr, "TrySelectUserWithoutInteraction"}, + {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, {60, nullptr, "ListOpenContextStoredUsers"}, {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 3cac1b4ff..968263846 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> #include <random> +#include <fmt/format.h> + #include "common/file_util.h" #include "core/hle/service/acc/profile_manager.h" #include "core/settings.h" @@ -39,6 +42,19 @@ UUID UUID::Generate() { return UUID{distribution(gen), distribution(gen)}; } +std::string UUID::Format() const { + return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); +} + +std::string UUID::FormatSwitch() const { + std::array<u8, 16> s{}; + std::memcpy(s.data(), uuid.data(), sizeof(u128)); + return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" + ":02x}{:02x}{:02x}{:02x}{:02x}", + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], + s[12], s[13], s[14], s[15]); +} + ProfileManager::ProfileManager() { ParseUserSaveFile(); @@ -195,7 +211,7 @@ std::size_t ProfileManager::GetOpenUserCount() const { /// Checks if a user id exists in our profile manager bool ProfileManager::UserExists(UUID uuid) const { - return GetUserIndex(uuid) != std::nullopt; + return GetUserIndex(uuid).has_value(); } bool ProfileManager::UserExistsIndex(std::size_t index) const { @@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() { return; } - for (std::size_t i = 0; i < MAX_USERS; ++i) { - const auto& user = data.users[i]; + for (const auto& user : data.users) { + if (user.uuid == UUID(INVALID_UUID)) { + continue; + } - if (user.uuid != UUID(INVALID_UUID)) - AddUser({user.uuid, user.username, user.timestamp, {}, false}); + AddUser({user.uuid, user.username, user.timestamp, {}, false}); } std::stable_partition(profiles.begin(), profiles.end(), diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 1cd2e51b2..d2d8e6c6b 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -42,22 +42,14 @@ struct UUID { void Invalidate() { uuid = INVALID_UUID; } - std::string Format() const { - return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); - } - std::string FormatSwitch() const { - std::array<u8, 16> s{}; - std::memcpy(s.data(), uuid.data(), sizeof(u128)); - return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" - ":02x}{:02x}{:02x}{:02x}{:02x}", - s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], - s[12], s[13], s[14], s[15]); - } + std::string Format() const; + std::string FormatSwitch() const; }; static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); -using ProfileUsername = std::array<u8, 0x20>; +constexpr std::size_t profile_username_size = 32; +using ProfileUsername = std::array<u8, profile_username_size>; using ProfileData = std::array<u8, MAX_DATA>; using UserIDArray = std::array<UUID, MAX_USERS>; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 59aafd616..0477ce66e 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -338,7 +338,54 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c LOG_WARNING(Service_AM, "(STUBBED) called"); } -ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { +AppletMessageQueue::AppletMessageQueue() { + auto& kernel = Core::System::GetInstance().Kernel(); + on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, + "AMMessageQueue:OnMessageRecieved"); + on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "AMMessageQueue:OperationModeChanged"); +} + +AppletMessageQueue::~AppletMessageQueue() = default; + +const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { + return on_new_message; +} + +const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { + return on_operation_mode_changed; +} + +void AppletMessageQueue::PushMessage(AppletMessage msg) { + messages.push(msg); + on_new_message->Signal(); +} + +AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + if (messages.empty()) { + on_new_message->Clear(); + return AppletMessage::NoMessage; + } + auto msg = messages.front(); + messages.pop(); + if (messages.empty()) { + on_new_message->Clear(); + } + return msg; +} + +std::size_t AppletMessageQueue::GetMessageCount() const { + return messages.size(); +} + +void AppletMessageQueue::OperationModeChanged() { + PushMessage(AppletMessage::OperationModeChanged); + PushMessage(AppletMessage::PerformanceModeChanged); + on_operation_mode_changed->Signal(); +} + +ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, @@ -388,21 +435,19 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { - event->Signal(); - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event); + rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(15); + rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { @@ -414,13 +459,11 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { - event->Signal(); - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event); + rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { @@ -444,7 +487,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { @@ -454,7 +497,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked : APM::PerformanceMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { @@ -743,7 +786,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { Account::ProfileManager profile_manager{}; const auto uuid = profile_manager.GetUser(Settings::values.current_user); - ASSERT(uuid != std::nullopt); + ASSERT(uuid); params.current_user = uuid->uuid; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -840,8 +883,12 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { - std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); - std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); + auto message_queue = std::make_shared<AppletMessageQueue>(); + message_queue->PushMessage( + AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot + + std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); + std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); std::make_shared<IdleSys>()->InstallAsService(service_manager); std::make_shared<OMM>()->InstallAsService(service_manager); std::make_shared<SPSM>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 095f94851..2f1c20bce 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -5,6 +5,7 @@ #pragma once #include <memory> +#include <queue> #include "core/hle/service/service.h" namespace Kernel { @@ -39,6 +40,31 @@ enum SystemLanguage { TraditionalChinese = 16, }; +class AppletMessageQueue { +public: + enum class AppletMessage : u32 { + NoMessage = 0, + FocusStateChanged = 15, + OperationModeChanged = 30, + PerformanceModeChanged = 31, + }; + + AppletMessageQueue(); + ~AppletMessageQueue(); + + const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; + const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; + void PushMessage(AppletMessage msg); + AppletMessage PopMessage(); + std::size_t GetMessageCount() const; + void OperationModeChanged(); + +private: + std::queue<AppletMessage> messages; + Kernel::SharedPtr<Kernel::Event> on_new_message; + Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; +}; + class IWindowController final : public ServiceFramework<IWindowController> { public: IWindowController(); @@ -102,7 +128,7 @@ private: class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { public: - ICommonStateGetter(); + explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue); ~ICommonStateGetter() override; private: @@ -126,6 +152,7 @@ private: void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); Kernel::SharedPtr<Kernel::Event> event; + std::shared_ptr<AppletMessageQueue> msg_queue; }; class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 68ea778e8..ec93e3529 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -12,8 +12,10 @@ namespace Service::AM { class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { public: - explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) { + explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, @@ -32,7 +34,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ICommonStateGetter>(); + rb.PushIpcInterface<ICommonStateGetter>(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -93,12 +95,15 @@ private: } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; }; class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { public: - explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) { + explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, @@ -119,7 +124,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ICommonStateGetter>(); + rb.PushIpcInterface<ICommonStateGetter>(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -186,31 +191,34 @@ private: LOG_DEBUG(Service_AM, "called"); } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; }; void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISystemAppletProxy>(nvflinger); + rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); + rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); + rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } -AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) { +AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, @@ -228,4 +236,8 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) AppletAE::~AppletAE() = default; +const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const { + return msg_queue; +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 1ed77baa4..902db2665 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -17,15 +17,19 @@ namespace AM { class AppletAE final : public ServiceFramework<AppletAE> { public: - explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); + explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue); ~AppletAE() override; + const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; + private: void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 60717afd9..20c8d5fff 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -12,8 +12,10 @@ namespace Service::AM { class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { public: - explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) { + explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -70,7 +72,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ICommonStateGetter>(); + rb.PushIpcInterface<ICommonStateGetter>(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -89,17 +91,20 @@ private: } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; }; void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationProxy>(nvflinger); + rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } -AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) { +AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue) + : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; @@ -108,4 +113,8 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) AppletOE::~AppletOE() = default; +const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { + return msg_queue; +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 60cfdfd9d..bbd0108ef 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -17,13 +17,17 @@ namespace AM { class AppletOE final : public ServiceFramework<AppletOE> { public: - explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); + explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, + std::shared_ptr<AppletMessageQueue> msg_queue); ~AppletOE() override; + const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; + private: void OpenApplicationProxy(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index fac6785a5..d3ea57ea7 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -28,13 +28,13 @@ public: {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, {3, &IAudioRenderer::GetState, "GetState"}, - {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, + {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"}, {5, &IAudioRenderer::Start, "Start"}, {6, &IAudioRenderer::Stop, "Stop"}, {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, - {8, nullptr, "SetRenderingTimeLimit"}, - {9, nullptr, "GetRenderingTimeLimit"}, - {10, nullptr, "RequestUpdateAuto"}, + {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, + {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, + {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"}, {11, nullptr, "ExecuteAudioRendererRendering"}, }; // clang-format on @@ -79,7 +79,7 @@ private: LOG_DEBUG(Service_Audio, "called"); } - void RequestUpdate(Kernel::HLERequestContext& ctx) { + void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -110,8 +110,29 @@ private: LOG_WARNING(Service_Audio, "(STUBBED) called"); } + void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + rendering_time_limit_percent = rp.Pop<u32>(); + ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}", + rendering_time_limit_percent); + } + + void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Audio, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(rendering_time_limit_percent); + } + Kernel::SharedPtr<Kernel::Event> system_event; std::unique_ptr<AudioCore::AudioRenderer> renderer; + u32 rendering_time_limit_percent = 100; }; class IAudioDevice final : public ServiceFramework<IAudioDevice> { diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 7168c6a10..783c39503 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -161,7 +161,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); std::size_t worker_sz = WorkerBufferSize(channel_count); - ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); + ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ static_cast<OpusDecoder*>(operator new(worker_sz))}; if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 234a8687b..a92cf7815 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -309,6 +309,16 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, return save_data_factory->Open(space, save_struct); } +ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { + LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); + + if (save_data_factory == nullptr) { + return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); + } + + return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space)); +} + ResultVal<FileSys::VirtualDir> OpenSDMC() { LOG_TRACE(Service_FS, "Opening SDMC"); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index b18652a68..e38f02869 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -45,6 +45,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora FileSys::ContentRecordType type); ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct); +ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); ResultVal<FileSys::VirtualDir> OpenSDMC(); std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c1c83a11d..b9a1d5105 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -11,6 +11,7 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/hex_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/directory.h" @@ -451,7 +452,147 @@ private: VfsDirectoryServiceWrapper backend; }; +class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { +public: + explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) + : ServiceFramework("ISaveDataInfoReader") { + static const FunctionInfo functions[] = { + {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, + }; + RegisterHandlers(functions); + + FindAllSaves(space); + } + + void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index); + const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries); + const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(actual_entries)); + } + +private: + static u64 stoull_be(std::string_view str) { + if (str.size() != 16) + return 0; + + const auto bytes = Common::HexStringToArray<0x8>(str); + u64 out{}; + std::memcpy(&out, bytes.data(), sizeof(u64)); + + return Common::swap64(out); + } + + void FindAllSaves(FileSys::SaveDataSpaceId space) { + const auto save_root = OpenSaveDataSpace(space); + ASSERT(save_root.Succeeded()); + + for (const auto& type : (*save_root)->GetSubdirectories()) { + if (type->GetName() == "save") { + for (const auto& save_id : type->GetSubdirectories()) { + for (const auto& user_id : save_id->GetSubdirectories()) { + const auto save_id_numeric = stoull_be(save_id->GetName()); + auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + + if (save_id_numeric != 0) { + // System Save Data + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::SystemSaveData, + {}, + user_id_numeric, + save_id_numeric, + 0, + user_id->GetSize(), + {}, + }); + + continue; + } + + for (const auto& title_id : user_id->GetSubdirectories()) { + const auto device = + std::all_of(user_id_numeric.begin(), user_id_numeric.end(), + [](u8 val) { return val == 0; }); + info.emplace_back(SaveDataInfo{ + 0, + space, + device ? FileSys::SaveDataType::DeviceSaveData + : FileSys::SaveDataType::SaveData, + {}, + user_id_numeric, + save_id_numeric, + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + }); + } + } + } + } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { + // Temporary Storage + for (const auto& user_id : type->GetSubdirectories()) { + for (const auto& title_id : user_id->GetSubdirectories()) { + if (!title_id->GetFiles().empty() || + !title_id->GetSubdirectories().empty()) { + auto user_id_numeric = + Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::TemporaryStorage, + {}, + user_id_numeric, + stoull_be(type->GetName()), + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + }); + } + } + } + } + } + } + + struct SaveDataInfo { + u64_le save_id_unknown; + FileSys::SaveDataSpaceId space; + FileSys::SaveDataType type; + INSERT_PADDING_BYTES(0x6); + std::array<u8, 0x10> user_id; + u64_le save_id; + u64_le title_id; + u64_le save_image_size; + INSERT_PADDING_BYTES(0x28); + }; + static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); + + std::vector<SaveDataInfo> info; + u64 next_entry_index = 0; +}; + FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { + // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "MountContent"}, {1, &FSP_SRV::Initialize, "Initialize"}, @@ -485,7 +626,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {58, nullptr, "ReadSaveDataFileSystemExtraData"}, {59, nullptr, "WriteSaveDataFileSystemExtraData"}, {60, nullptr, "OpenSaveDataInfoReader"}, - {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, + {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, {62, nullptr, "OpenCacheStorageList"}, {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, {65, nullptr, "UpdateSaveDataMacForDebug"}, @@ -544,6 +685,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {1009, nullptr, "GetAndClearMemoryReportInfo"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, }; + // clang-format on RegisterHandlers(functions); } @@ -618,6 +760,15 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { MountSaveData(ctx); } +void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space)); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4aa0358cb..e7abec0a3 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -25,6 +25,7 @@ private: void CreateSaveData(Kernel::HLERequestContext& ctx); void MountSaveData(Kernel::HLERequestContext& ctx); void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); + void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4b4d1324f..56c415e4e 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -310,6 +310,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { dual_entry.pad_states.raw = pad_state.raw; dual_entry.l_stick = lstick_entry; dual_entry.r_stick = rstick_entry; + break; case NPadControllerType::JoyLeft: left_entry.connection_status.raw = 0; @@ -392,8 +393,10 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { } void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { + styleset_changed_event->Signal(); hold_type = joy_hold_type; } + Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { return hold_type; } @@ -427,6 +430,9 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, } Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { + // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should + // be signalled at least once, and signaled after a new controller is connected? + styleset_changed_event->Signal(); return styleset_changed_event; } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index a9aa9ec78..a45fd4954 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -96,6 +96,8 @@ public: // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); + + ReloadInputDevices(); } void ActivateController(HidController controller) { diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index c1af878fe..1d6e7756f 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -212,7 +212,7 @@ private: IPC::ResponseBuilder rb{ctx, 2}; auto amiibo = nfp_interface.GetAmiiboBuffer(); TagInfo tag_info{}; - std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size())); + tag_info.uuid = amiibo.uuid; tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); tag_info.protocol = 1; // TODO(ogniK): Figure out actual values diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 07c1381fe..1d2978f24 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/ns/ns.h" @@ -118,7 +121,7 @@ public: {305, nullptr, "TerminateSystemApplet"}, {306, nullptr, "LaunchOverlayApplet"}, {307, nullptr, "TerminateOverlayApplet"}, - {400, nullptr, "GetApplicationControlData"}, + {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, {401, nullptr, "InvalidateAllApplicationControlCache"}, {402, nullptr, "RequestDownloadApplicationControlData"}, {403, nullptr, "GetMaxApplicationControlCacheCount"}, @@ -243,6 +246,65 @@ public: RegisterHandlers(functions); } + + void GetApplicationControlData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto flag = rp.PopRaw<u64>(); + LOG_DEBUG(Service_NS, "called with flag={:016X}", flag); + + const auto title_id = rp.PopRaw<u64>(); + + const auto size = ctx.GetWriteBufferSize(); + + const FileSys::PatchManager pm{title_id}; + const auto control = pm.GetControlMetadata(); + + std::vector<u8> out; + + if (control.first != nullptr) { + if (size < 0x4000) { + LOG_ERROR(Service_NS, + "output buffer is too small! (actual={:016X}, expected_min=0x4000)", + size); + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(DarkLordZach): Find a better error code for this. + rb.Push(ResultCode(-1)); + return; + } + + out.resize(0x4000); + const auto bytes = control.first->GetRawBytes(); + std::memcpy(out.data(), bytes.data(), bytes.size()); + } else { + LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.", + title_id); + out.resize(std::min<u64>(0x4000, size)); + } + + if (control.second != nullptr) { + if (size < 0x4000 + control.second->GetSize()) { + LOG_ERROR(Service_NS, + "output buffer is too small! (actual={:016X}, expected_min={:016X})", + size, 0x4000 + control.second->GetSize()); + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(DarkLordZach): Find a better error code for this. + rb.Push(ResultCode(-1)); + return; + } + + out.resize(0x4000 + control.second->GetSize()); + control.second->Read(out.data() + 0x4000, control.second->GetSize()); + } else { + LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.", + title_id); + } + + ctx.WriteBuffer(out); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(out.size())); + } }; class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index fd98d541d..630ebbfc7 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -31,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) buffer_wait_event->Signal(); } -boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { +std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { // Only consider free buffers. Buffers become free once again after they've been Acquired // and Released by the compositor, see the NVFlinger::Compose method. @@ -44,7 +44,7 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { }); if (itr == queue.end()) { - return boost::none; + return {}; } itr->status = Buffer::Status::Dequeued; @@ -70,12 +70,12 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, itr->crop_rect = crop_rect; } -boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { +std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { return buffer.status == Buffer::Status::Queued; }); if (itr == queue.end()) - return boost::none; + return {}; itr->status = Buffer::Status::Acquired; return *itr; } diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 50b767732..8cff5eb71 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -4,8 +4,9 @@ #pragma once +#include <optional> #include <vector> -#include <boost/optional.hpp> + #include "common/common_funcs.h" #include "common/math_util.h" #include "common/swap.h" @@ -57,9 +58,9 @@ public: /// Rotate source image 90 degrees clockwise Rotate90 = 0x04, /// Rotate source image 180 degrees - Roate180 = 0x03, + Rotate180 = 0x03, /// Rotate source image 270 degrees clockwise - Roate270 = 0x07, + Rotate270 = 0x07, }; struct Buffer { @@ -73,11 +74,11 @@ public: }; void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); - boost::optional<u32> DequeueBuffer(u32 width, u32 height); + std::optional<u32> DequeueBuffer(u32 width, u32 height); const IGBPBuffer& RequestBuffer(u32 slot) const; void QueueBuffer(u32 slot, BufferTransformFlags transform, const MathUtil::Rectangle<int>& crop_rect); - boost::optional<const Buffer&> AcquireBuffer(); + std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); void ReleaseBuffer(u32 slot); u32 Query(QueryType type); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index d47b6f659..214e6d1b3 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include <algorithm> -#include <boost/optional.hpp> +#include <optional> #include "common/alignment.h" #include "common/assert.h" @@ -134,7 +134,7 @@ void NVFlinger::Compose() { MicroProfileFlip(); - if (buffer == boost::none) { + if (!buffer) { auto& system_instance = Core::System::GetInstance(); // There was no queued buffer to draw, render previous frame @@ -143,7 +143,7 @@ void NVFlinger::Compose() { continue; } - auto& igbp_buffer = buffer->igbp_buffer; + auto& igbp_buffer = buffer->get().igbp_buffer; // Now send the buffer to the GPU for drawing. // TODO(Subv): Support more than just disp0. The display device selection is probably based @@ -152,10 +152,10 @@ void NVFlinger::Compose() { ASSERT(nvdisp); nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, - igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform, - buffer->crop_rect); + igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, + buffer->get().transform, buffer->get().crop_rect); - buffer_queue->ReleaseBuffer(buffer->slot); + buffer_queue->ReleaseBuffer(buffer->get().slot); } } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index a4cf45267..1ec340466 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -80,8 +80,8 @@ namespace Service { * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. */ -static std::string MakeFunctionString(const char* name, const char* port_name, - const u32* cmd_buff) { +[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name, + const u32* cmd_buff) { // Number of params == bits 0-5 + bits 6-11 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 44a6717d0..69c260408 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp @@ -3,18 +3,23 @@ // Refer to the license.txt file included. #include <algorithm> +#include <chrono> #include <cstdlib> +#include <ctime> +#include <functional> #include <vector> #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/spl/csrng.h" #include "core/hle/service/spl/module.h" #include "core/hle/service/spl/spl.h" +#include "core/settings.h" namespace Service::SPL { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) - : ServiceFramework(name), module(std::move(module)) {} + : ServiceFramework(name), module(std::move(module)), + rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {} Module::Interface::~Interface() = default; @@ -24,7 +29,7 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { std::size_t size = ctx.GetWriteBufferSize(); std::vector<u8> data(size); - std::generate(data.begin(), data.end(), std::rand); + std::generate(data.begin(), data.end(), rng); ctx.WriteBuffer(data); diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index 48fda6099..afa1f0295 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h @@ -4,6 +4,7 @@ #pragma once +#include <random> #include "core/hle/service/service.h" namespace Service::SPL { @@ -19,6 +20,9 @@ public: protected: std::shared_ptr<Module> module; + + private: + std::mt19937 rng; }; }; diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 18a5d71d5..e3cbd7004 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -21,7 +21,7 @@ Time::Time(std::shared_ptr<Module> time, const char* name) {102, nullptr, "GetStandardUserSystemClockInitialYear"}, {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, - {400, nullptr, "GetClockSnapshot"}, + {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, {501, nullptr, "CalculateSpanBetween"}, diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 28fd8debc..85e7b1195 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -15,6 +15,44 @@ namespace Service::Time { +static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, + CalendarAdditionalInfo& additional_info, + [[maybe_unused]] const TimeZoneRule& /*rule*/) { + const std::time_t time(posix_time); + const std::tm* tm = std::localtime(&time); + if (tm == nullptr) { + calendar_time = {}; + additional_info = {}; + return; + } + calendar_time.year = tm->tm_year + 1900; + calendar_time.month = tm->tm_mon + 1; + calendar_time.day = tm->tm_mday; + calendar_time.hour = tm->tm_hour; + calendar_time.minute = tm->tm_min; + calendar_time.second = tm->tm_sec; + + additional_info.day_of_week = tm->tm_wday; + additional_info.day_of_year = tm->tm_yday; + std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); + additional_info.utc_offset = 0; +} + +static u64 CalendarToPosix(const CalendarTime& calendar_time, + [[maybe_unused]] const TimeZoneRule& /*rule*/) { + std::tm time{}; + time.tm_year = calendar_time.year - 1900; + time.tm_mon = calendar_time.month - 1; + time.tm_mday = calendar_time.day; + + time.tm_hour = calendar_time.hour; + time.tm_min = calendar_time.minute; + time.tm_sec = calendar_time.second; + + std::time_t epoch_time = std::mktime(&time); + return static_cast<u64>(epoch_time); +} + class ISystemClock final : public ServiceFramework<ISystemClock> { public: ISystemClock() : ServiceFramework("ISystemClock") { @@ -80,8 +118,8 @@ public: {5, nullptr, "GetTimeZoneRuleVersion"}, {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, - {201, nullptr, "ToPosixTime"}, - {202, nullptr, "ToPosixTimeWithMyRule"}, + {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, + {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, }; RegisterHandlers(functions); } @@ -151,24 +189,29 @@ private: rb.PushRaw(additional_info); } - void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, - CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) { - std::time_t t(posix_time); - std::tm* tm = std::localtime(&t); - if (!tm) { - return; - } - calendar_time.year = tm->tm_year + 1900; - calendar_time.month = tm->tm_mon + 1; - calendar_time.day = tm->tm_mday; - calendar_time.hour = tm->tm_hour; - calendar_time.minute = tm->tm_min; - calendar_time.second = tm->tm_sec; - - additional_info.day_of_week = tm->tm_wday; - additional_info.day_of_year = tm->tm_yday; - std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); - additional_info.utc_offset = 0; + void ToPosixTime(Kernel::HLERequestContext& ctx) { + // TODO(ogniK): Figure out how to handle multiple times + LOG_WARNING(Service_Time, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + auto calendar_time = rp.PopRaw<CalendarTime>(); + auto posix_time = CalendarToPosix(calendar_time, {}); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u32>(1); // Amount of times we're returning + ctx.WriteBuffer(&posix_time, sizeof(u64)); + } + + void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_Time, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + auto calendar_time = rp.PopRaw<CalendarTime>(); + auto posix_time = CalendarToPosix(calendar_time, {}); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u32>(1); // Amount of times we're returning + ctx.WriteBuffer(&posix_time, sizeof(u64)); } }; @@ -207,6 +250,55 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c LOG_DEBUG(Service_Time, "called"); } +void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called"); + + IPC::RequestParser rp{ctx}; + auto unknown_u8 = rp.PopRaw<u8>(); + + ClockSnapshot clock_snapshot{}; + + const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + .count()}; + CalendarTime calendar_time{}; + const std::time_t time(time_since_epoch); + const std::tm* tm = std::localtime(&time); + if (tm == nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code + return; + } + SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / + 1000}; + + LocationName location_name{"UTC"}; + calendar_time.year = tm->tm_year + 1900; + calendar_time.month = tm->tm_mon + 1; + calendar_time.day = tm->tm_mday; + calendar_time.hour = tm->tm_hour; + calendar_time.minute = tm->tm_min; + calendar_time.second = tm->tm_sec; + clock_snapshot.system_posix_time = time_since_epoch; + clock_snapshot.network_posix_time = time_since_epoch; + clock_snapshot.system_calendar_time = calendar_time; + clock_snapshot.network_calendar_time = calendar_time; + + CalendarAdditionalInfo additional_info{}; + PosixToCalendar(time_since_epoch, calendar_time, additional_info, {}); + + clock_snapshot.system_calendar_info = additional_info; + clock_snapshot.network_calendar_info = additional_info; + + clock_snapshot.steady_clock_timepoint = steady_clock_time_point; + clock_snapshot.location_name = location_name; + clock_snapshot.clock_auto_adjustment_enabled = 1; + clock_snapshot.ipc_u8 = unknown_u8; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); +} + Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) : ServiceFramework(name), time(std::move(time)) {} diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 5659ecad3..77871ae07 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include "common/common_funcs.h" #include "core/hle/service/service.h" namespace Service::Time { @@ -53,6 +54,23 @@ struct SystemClockContext { static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext structure has incorrect size"); +struct ClockSnapshot { + SystemClockContext user_clock_context; + SystemClockContext network_clock_context; + s64_le system_posix_time; + s64_le network_posix_time; + CalendarTime system_calendar_time; + CalendarTime network_calendar_time; + CalendarAdditionalInfo system_calendar_info; + CalendarAdditionalInfo network_calendar_info; + SteadyClockTimePoint steady_clock_timepoint; + LocationName location_name; + u8 clock_auto_adjustment_enabled; + u8 ipc_u8; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size"); + class Module final { public: class Interface : public ServiceFramework<Interface> { @@ -65,6 +83,7 @@ public: void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); void GetTimeZoneService(Kernel::HLERequestContext& ctx); void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); + void GetClockSnapshot(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> time; diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index c489da071..f0a831d45 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -132,11 +132,11 @@ public: // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "BindNoticeEvent"}, - {1, nullptr, "Unknown1"}, + {1, nullptr, "UnbindNoticeEvent"}, {2, nullptr, "GetStatus"}, {3, nullptr, "GetNotice"}, - {4, nullptr, "Unknown2"}, - {5, nullptr, "Unknown3"}, + {4, nullptr, "EnablePowerRequestNotice"}, + {5, nullptr, "DisablePowerRequestNotice"}, {6, nullptr, "ReplyPowerRequest"}, }; // clang-format on diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 184537daa..d764b2406 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -6,9 +6,10 @@ #include <array> #include <cstring> #include <memory> +#include <optional> #include <type_traits> #include <utility> -#include <boost/optional.hpp> + #include "common/alignment.h" #include "common/assert.h" #include "common/common_funcs.h" @@ -506,9 +507,9 @@ private: IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; const u32 width{request.data.width}; const u32 height{request.data.height}; - boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); + std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); - if (slot != boost::none) { + if (slot) { // Buffer is available IGBPDequeueBufferResponseParcel response{*slot}; ctx.WriteBuffer(response.Serialize()); @@ -520,7 +521,7 @@ private: Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available auto buffer_queue = nv_flinger->GetBufferQueue(id); - boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); + std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); IGBPDequeueBufferResponseParcel response{*slot}; ctx.WriteBuffer(response.Serialize()); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index e562b3a04..7686634bf 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -6,10 +6,11 @@ #include <iosfwd> #include <memory> +#include <optional> #include <string> #include <utility> #include <vector> -#include <boost/optional.hpp> + #include "common/common_types.h" #include "core/file_sys/vfs.h" @@ -145,7 +146,7 @@ public: * information. * @returns A pair with the optional system mode, and and the status. */ - virtual std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() { + virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() { // 96MB allocated to the application. return std::make_pair(2, ResultStatus::Success); } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index bc8e402a8..c8e491fec 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -12,10 +12,12 @@ #include "common/swap.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" +#include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs_offset.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/vm_manager.h" +#include "core/hle/service/filesystem/filesystem.h" #include "core/loader/nro.h" #include "core/loader/nso.h" #include "core/memory.h" @@ -208,6 +210,9 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { return ResultStatus::ErrorLoadingNRO; } + if (romfs != nullptr) + Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); + process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 014298ed6..70abd856a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -4,9 +4,9 @@ #include <algorithm> #include <cstring> +#include <optional> #include <utility> -#include <boost/optional.hpp> #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" diff --git a/src/core/memory_hook.h b/src/core/memory_hook.h index 0269c7ff1..940777107 100644 --- a/src/core/memory_hook.h +++ b/src/core/memory_hook.h @@ -5,7 +5,8 @@ #pragma once #include <memory> -#include <boost/optional.hpp> +#include <optional> + #include "common/common_types.h" namespace Memory { @@ -18,19 +19,19 @@ namespace Memory { * * A hook may be mapped to multiple regions of memory. * - * If a boost::none or false is returned from a function, the read/write request is passed through + * If a std::nullopt or false is returned from a function, the read/write request is passed through * to the underlying memory region. */ class MemoryHook { public: virtual ~MemoryHook(); - virtual boost::optional<bool> IsValidAddress(VAddr addr) = 0; + virtual std::optional<bool> IsValidAddress(VAddr addr) = 0; - virtual boost::optional<u8> Read8(VAddr addr) = 0; - virtual boost::optional<u16> Read16(VAddr addr) = 0; - virtual boost::optional<u32> Read32(VAddr addr) = 0; - virtual boost::optional<u64> Read64(VAddr addr) = 0; + virtual std::optional<u8> Read8(VAddr addr) = 0; + virtual std::optional<u16> Read16(VAddr addr) = 0; + virtual std::optional<u32> Read32(VAddr addr) = 0; + virtual std::optional<u64> Read64(VAddr addr) = 0; virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; diff --git a/src/core/settings.h b/src/core/settings.h index 0af9dd416..e424479f2 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -6,6 +6,7 @@ #include <array> #include <atomic> +#include <optional> #include <string> #include "common/common_types.h" @@ -114,8 +115,9 @@ struct Values { // System bool use_docked_mode; bool enable_nfc; - int current_user; - int language_index; + std::optional<u32> rng_seed; + s32 current_user; + s32 language_index; // Controls std::array<std::string, NativeButton::NumButtons> buttons; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 0de13edd3..a3b08c740 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() { backend = nullptr; } +bool TelemetrySession::SubmitTestcase() { +#ifdef ENABLE_WEB_SERVICE + field_collection.Accept(*backend); + return backend->SubmitTestcase(); +#else + return false; +#endif +} + } // namespace Core diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 2a4845797..023612b79 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -31,6 +31,12 @@ public: field_collection.AddField(type, name, std::move(value)); } + /** + * Submits a Testcase. + * @returns A bool indicating whether the submission succeeded + */ + bool SubmitTestcase(); + private: Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields |