diff options
Diffstat (limited to 'src/core')
35 files changed, 868 insertions, 196 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5462decee..877a9e353 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -70,6 +70,8 @@ add_library(core STATIC file_sys/sdmc_factory.h file_sys/submission_package.cpp file_sys/submission_package.h + file_sys/system_archive/mii_model.cpp + file_sys/system_archive/mii_model.h file_sys/system_archive/ng_word.cpp file_sys/system_archive/ng_word.h file_sys/system_archive/system_archive.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 20d64f3b0..3d0978cbf 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -104,7 +104,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, return vfs->OpenFile(path, FileSys::Mode::Read); } struct System::Impl { - explicit Impl(System& system) : kernel{system}, cpu_core_manager{system}, reporter{system} {} + explicit Impl(System& system) + : kernel{system}, cpu_core_manager{system}, applet_manager{system}, reporter{system} {} Cpu& CurrentCpuCore() { return cpu_core_manager.GetCurrentCore(); diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 6dd633363..46aceec3d 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -37,6 +37,7 @@ namespace Core::Crypto { constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; +constexpr u64 FULL_TICKET_SIZE = 0x400; using namespace Common; @@ -55,6 +56,99 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, }; +namespace { +template <std::size_t Size> +bool IsAllZeroArray(const std::array<u8, Size>& array) { + return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); +} +} // namespace + +u64 GetSignatureTypeDataSize(SignatureType type) { + switch (type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + return 0x200; + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return 0x100; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return 0x3C; + } + UNREACHABLE(); +} + +u64 GetSignatureTypePaddingSize(SignatureType type) { + switch (type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return 0x3C; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return 0x40; + } + UNREACHABLE(); +} + +SignatureType Ticket::GetSignatureType() const { + if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { + return ticket->sig_type; + } + if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { + return ticket->sig_type; + } + if (auto ticket = std::get_if<ECDSATicket>(&data)) { + return ticket->sig_type; + } + + UNREACHABLE(); +} + +TicketData& Ticket::GetData() { + if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if<ECDSATicket>(&data)) { + return ticket->data; + } + + UNREACHABLE(); +} + +const TicketData& Ticket::GetData() const { + if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if<ECDSATicket>(&data)) { + return ticket->data; + } + + UNREACHABLE(); +} + +u64 Ticket::GetSize() const { + const auto sig_type = GetSignatureType(); + + return sizeof(SignatureType) + GetSignatureTypeDataSize(sig_type) + + GetSignatureTypePaddingSize(sig_type) + sizeof(TicketData); +} + +Ticket Ticket::SynthesizeCommon(Key128 title_key, const std::array<u8, 16>& rights_id) { + RSA2048Ticket out{}; + out.sig_type = SignatureType::RSA_2048_SHA256; + out.data.rights_id = rights_id; + out.data.title_key_common = title_key; + return Ticket{out}; +} + Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { Key128 out{}; @@ -135,6 +229,27 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { } } +RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const { + if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) + return {}; + + const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); + + std::vector<u8> extended_iv(eticket_extended_kek.begin(), eticket_extended_kek.begin() + 0x10); + std::array<u8, 0x230> extended_dec{}; + AESCipher<Key128> rsa_1(eticket_final, Mode::CTR); + rsa_1.SetIV(extended_iv); + rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, + extended_dec.data(), Op::Decrypt); + + RSAKeyPair<2048> rsa_key{}; + std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); + std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); + std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); + + return rsa_key; +} + Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB); Key128 mac_key{}; @@ -237,7 +352,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke return Loader::ResultStatus::Success; } -std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { +std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) { if (!ticket_save.IsOpen()) return {}; @@ -246,14 +361,14 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { return {}; } - std::vector<TicketRaw> out; + std::vector<Ticket> out; for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && buffer[offset + 3] == 0x0) { out.emplace_back(); auto& next = out.back(); - std::memcpy(&next, buffer.data() + offset, sizeof(TicketRaw)); - offset += next.size(); + std::memcpy(&next, buffer.data() + offset, sizeof(Ticket)); + offset += FULL_TICKET_SIZE; } } @@ -305,29 +420,23 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { return offset; } -std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, +std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, const RSAKeyPair<2048>& key) { - u32 cert_authority; - std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); - if (cert_authority == 0) + const auto issuer = ticket.GetData().issuer; + if (issuer == std::array<u8, 0x40>{}) return {}; - if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { - LOG_INFO(Crypto, - "Attempting to parse ticket with non-standard certificate authority {:08X}.", - cert_authority); + if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { + LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); } - Key128 rights_id; - std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); + Key128 rights_id = ticket.GetData().rights_id; if (rights_id == Key128{}) return {}; - Key128 key_temp{}; - - if (!std::any_of(ticket.begin() + 0x190, ticket.begin() + 0x280, [](u8 b) { return b != 0; })) { - std::memcpy(key_temp.data(), ticket.data() + 0x180, key_temp.size()); - return std::make_pair(rights_id, key_temp); + if (!std::any_of(ticket.GetData().title_key_common_pad.begin(), + ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) { + return std::make_pair(rights_id, ticket.GetData().title_key_common); } mbedtls_mpi D; // RSA Private Exponent @@ -342,7 +451,7 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size()); mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size()); - mbedtls_mpi_read_binary(&S, ticket.data() + 0x180, 0x100); + mbedtls_mpi_read_binary(&S, ticket.GetData().title_key_block.data(), 0x100); mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr); @@ -366,6 +475,7 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, return {}; ASSERT(*offset > 0); + Key128 key_temp{}; std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size()); return std::make_pair(rights_id, key_temp); @@ -450,6 +560,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); + } else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) { + eticket_extended_kek = Common::HexStringToArray<576>(out[1]); } else { for (const auto& kv : KEYS_VARIABLE_LENGTH) { if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) @@ -862,20 +974,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { // Titlekeys data.DecryptProdInfo(GetBISKey(0)); - const auto eticket_extended_kek = data.GetETicketExtendedKek(); + eticket_extended_kek = data.GetETicketExtendedKek(); + WriteKeyToFile(KeyCategory::Console, "eticket_extended_kek", eticket_extended_kek); + PopulateTickets(); +} - std::vector<u8> extended_iv(0x10); - std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); - std::array<u8, 0x230> extended_dec{}; - AESCipher<Key128> rsa_1(eticket_final, Mode::CTR); - rsa_1.SetIV(extended_iv); - rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, - extended_dec.data(), Op::Decrypt); +void KeyManager::PopulateTickets() { + const auto rsa_key = GetETicketRSAKey(); - RSAKeyPair<2048> rsa_key{}; - std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); - std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); - std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); + if (rsa_key == RSAKeyPair<2048>{}) + return; + + if (!common_tickets.empty() && !personal_tickets.empty()) + return; const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/80000000000000e1", @@ -886,19 +997,41 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { const auto blob2 = GetTicketblob(save2); auto res = GetTicketblob(save1); + const auto idx = res.size(); res.insert(res.end(), blob2.begin(), blob2.end()); - for (const auto& raw : res) { - const auto pair = ParseTicket(raw, rsa_key); + for (std::size_t i = 0; i < res.size(); ++i) { + const auto common = i < idx; + const auto pair = ParseTicket(res[i], rsa_key); if (!pair) continue; const auto& [rid, key] = *pair; u128 rights_id; std::memcpy(rights_id.data(), rid.data(), rid.size()); + + if (common) { + common_tickets[rights_id] = res[i]; + } else { + personal_tickets[rights_id] = res[i]; + } + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); } } +void KeyManager::SynthesizeTickets() { + for (const auto& key : s128_keys) { + if (key.first.type != S128KeyType::Titlekey) { + continue; + } + u128 rights_id{key.first.field1, key.first.field2}; + Key128 rights_id_2; + std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); + const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); + common_tickets.insert_or_assign(rights_id, ticket); + } +} + void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { if (key == Key128{}) return; @@ -997,6 +1130,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { DeriveBase(); } +const std::map<u128, Ticket>& KeyManager::GetCommonTickets() const { + return common_tickets; +} + +const std::map<u128, Ticket>& KeyManager::GetPersonalizedTickets() const { + return personal_tickets; +} + +bool KeyManager::AddTicketCommon(Ticket raw) { + const auto rsa_key = GetETicketRSAKey(); + if (rsa_key == RSAKeyPair<2048>{}) + return false; + + const auto pair = ParseTicket(raw, rsa_key); + if (!pair) + return false; + const auto& [rid, key] = *pair; + u128 rights_id; + std::memcpy(rights_id.data(), rid.data(), rid.size()); + common_tickets[rights_id] = raw; + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); + return true; +} + +bool KeyManager::AddTicketPersonalized(Ticket raw) { + const auto rsa_key = GetETicketRSAKey(); + if (rsa_key == RSAKeyPair<2048>{}) + return false; + + const auto pair = ParseTicket(raw, rsa_key); + if (!pair) + return false; + const auto& [rid, key] = *pair; + u128 rights_id; + std::memcpy(rights_id.data(), rid.data(), rid.size()); + common_tickets[rights_id] = raw; + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); + return true; +} + const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, {"eticket_rsa_kek_source", diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 22f268c65..7265c4171 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -9,8 +9,10 @@ #include <optional> #include <string> +#include <variant> #include <boost/container/flat_map.hpp> #include <fmt/format.h> +#include "common/common_funcs.h" #include "common/common_types.h" #include "core/crypto/partition_data_manager.h" #include "core/file_sys/vfs_types.h" @@ -30,7 +32,79 @@ constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180; using Key128 = std::array<u8, 0x10>; using Key256 = std::array<u8, 0x20>; using SHA256Hash = std::array<u8, 0x20>; -using TicketRaw = std::array<u8, 0x400>; + +enum class SignatureType { + RSA_4096_SHA1 = 0x10000, + RSA_2048_SHA1 = 0x10001, + ECDSA_SHA1 = 0x10002, + RSA_4096_SHA256 = 0x10003, + RSA_2048_SHA256 = 0x10004, + ECDSA_SHA256 = 0x10005, +}; + +u64 GetSignatureTypeDataSize(SignatureType type); +u64 GetSignatureTypePaddingSize(SignatureType type); + +enum class TitleKeyType : u8 { + Common = 0, + Personalized = 1, +}; + +struct TicketData { + std::array<u8, 0x40> issuer; + union { + std::array<u8, 0x100> title_key_block; + + struct { + Key128 title_key_common; + std::array<u8, 0xF0> title_key_common_pad; + }; + }; + + INSERT_PADDING_BYTES(0x1); + TitleKeyType type; + INSERT_PADDING_BYTES(0x3); + u8 revision; + INSERT_PADDING_BYTES(0xA); + u64 ticket_id; + u64 device_id; + std::array<u8, 0x10> rights_id; + u32 account_id; + INSERT_PADDING_BYTES(0x14C); +}; +static_assert(sizeof(TicketData) == 0x2C0, "TicketData has incorrect size."); + +struct RSA4096Ticket { + SignatureType sig_type; + std::array<u8, 0x200> sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; +}; + +struct RSA2048Ticket { + SignatureType sig_type; + std::array<u8, 0x100> sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; +}; + +struct ECDSATicket { + SignatureType sig_type; + std::array<u8, 0x3C> sig_data; + INSERT_PADDING_BYTES(0x40); + TicketData data; +}; + +struct Ticket { + std::variant<RSA4096Ticket, RSA2048Ticket, ECDSATicket> data; + + SignatureType GetSignatureType() const; + TicketData& GetData(); + const TicketData& GetData() const; + u64 GetSize() const; + + static Ticket SynthesizeCommon(Key128 title_key, const std::array<u8, 0x10>& rights_id); +}; static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); static_assert(sizeof(Key256) == 32, "Key256 must be 256 bytes big."); @@ -43,6 +117,19 @@ struct RSAKeyPair { std::array<u8, 4> exponent; }; +template <size_t bit_size, size_t byte_size> +bool operator==(const RSAKeyPair<bit_size, byte_size>& lhs, + const RSAKeyPair<bit_size, byte_size>& rhs) { + return std::tie(lhs.encryption_key, lhs.decryption_key, lhs.modulus, lhs.exponent) == + std::tie(rhs.encryption_key, rhs.decryption_key, rhs.modulus, rhs.exponent); +} + +template <size_t bit_size, size_t byte_size> +bool operator!=(const RSAKeyPair<bit_size, byte_size>& lhs, + const RSAKeyPair<bit_size, byte_size>& rhs) { + return !(lhs == rhs); +} + enum class KeyCategory : u8 { Standard, Title, @@ -151,22 +238,35 @@ public: static bool KeyFileExists(bool title); - // Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system save - // 8*43 and the private file to exist. + // Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system + // save 8*43 and the private file to exist. void DeriveSDSeedLazy(); bool BaseDeriveNecessary() const; void DeriveBase(); void DeriveETicket(PartitionDataManager& data); + void PopulateTickets(); + void SynthesizeTickets(); void PopulateFromPartitionData(PartitionDataManager& data); + const std::map<u128, Ticket>& GetCommonTickets() const; + const std::map<u128, Ticket>& GetPersonalizedTickets() const; + + bool AddTicketCommon(Ticket raw); + bool AddTicketPersonalized(Ticket raw); + private: std::map<KeyIndex<S128KeyType>, Key128> s128_keys; std::map<KeyIndex<S256KeyType>, Key256> s256_keys; + // Map from rights ID to ticket + std::map<u128, Ticket> common_tickets; + std::map<u128, Ticket> personal_tickets; + std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{}; std::array<std::array<u8, 0x90>, 0x20> keyblobs{}; + std::array<u8, 576> eticket_extended_kek{}; bool dev_mode; void LoadFromFile(const std::string& filename, bool is_title_keys); @@ -178,6 +278,8 @@ private: void DeriveGeneralPurposeKeys(std::size_t crypto_revision); + RSAKeyPair<2048> GetETicketRSAKey() const; + void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); @@ -195,11 +297,11 @@ std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblo std::optional<Key128> DeriveSDSeed(); Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys); -std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save); +std::vector<Ticket> 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) -std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, +// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority +// (offset 0x140-0x144 is zero) +std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, const RSAKeyPair<2048>& eticket_extended_key); } // namespace Core::Crypto diff --git a/src/core/file_sys/system_archive/mii_model.cpp b/src/core/file_sys/system_archive/mii_model.cpp new file mode 100644 index 000000000..6a9add87c --- /dev/null +++ b/src/core/file_sys/system_archive/mii_model.cpp @@ -0,0 +1,46 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/file_sys/system_archive/mii_model.h" +#include "core/file_sys/vfs_vector.h" + +namespace FileSys::SystemArchive { + +namespace MiiModelData { + +constexpr std::array<u8, 0x10> NFTR_STANDARD{'N', 'F', 'T', 'R', 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +constexpr std::array<u8, 0x10> NFSR_STANDARD{'N', 'F', 'S', 'R', 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +constexpr auto TEXTURE_LOW_LINEAR = NFTR_STANDARD; +constexpr auto TEXTURE_LOW_SRGB = NFTR_STANDARD; +constexpr auto TEXTURE_MID_LINEAR = NFTR_STANDARD; +constexpr auto TEXTURE_MID_SRGB = NFTR_STANDARD; +constexpr auto SHAPE_HIGH = NFSR_STANDARD; +constexpr auto SHAPE_MID = NFSR_STANDARD; + +} // namespace MiiModelData + +VirtualDir MiiModel() { + auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, + std::vector<VirtualDir>{}, "data"); + + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>( + MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat")); + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>( + MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat")); + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>( + MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat")); + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>( + MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat")); + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>( + MiiModelData::SHAPE_HIGH, "ShapeHigh.dat")); + out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>( + MiiModelData::SHAPE_MID, "ShapeMid.dat")); + + return std::move(out); +} + +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/mii_model.h b/src/core/file_sys/system_archive/mii_model.h new file mode 100644 index 000000000..6c2d9398b --- /dev/null +++ b/src/core/file_sys/system_archive/mii_model.h @@ -0,0 +1,13 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs_types.h" + +namespace FileSys::SystemArchive { + +VirtualDir MiiModel(); + +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp index c9722ed77..6d8445383 100644 --- a/src/core/file_sys/system_archive/system_archive.cpp +++ b/src/core/file_sys/system_archive/system_archive.cpp @@ -4,6 +4,7 @@ #include "common/logging/log.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/mii_model.h" #include "core/file_sys/system_archive/ng_word.h" #include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/system_archive/system_version.h" @@ -24,7 +25,7 @@ struct SystemArchiveDescriptor { constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{ {0x0100000000000800, "CertStore", nullptr}, {0x0100000000000801, "ErrorMessage", nullptr}, - {0x0100000000000802, "MiiModel", nullptr}, + {0x0100000000000802, "MiiModel", &MiiModel}, {0x0100000000000803, "BrowserDll", nullptr}, {0x0100000000000804, "Help", nullptr}, {0x0100000000000805, "SharedFont", nullptr}, diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 40cea1e7c..c7af87073 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -296,12 +296,6 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { } ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { - const auto end_addr = target + size; - const auto last_addr = end_addr - 1; - VAddr cur_addr = target; - - ResultCode result = RESULT_SUCCESS; - // Check how much memory we've already mapped. const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size); if (mapped_size_result.Failed()) { @@ -324,13 +318,16 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { // Keep track of the memory regions we unmap. std::vector<std::pair<u64, u64>> mapped_regions; + ResultCode result = RESULT_SUCCESS; // Iterate, trying to map memory. { - cur_addr = target; + const auto end_addr = target + size; + const auto last_addr = end_addr - 1; + VAddr cur_addr = target; auto iter = FindVMA(target); - ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -342,7 +339,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr); if (vma.state == MemoryState::Unmapped) { const auto map_res = - MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size, 0), 0, + MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size), 0, map_size, MemoryState::Heap, VMAPermission::ReadWrite); result = map_res.Code(); if (result.IsError()) { @@ -360,7 +357,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { // Advance to the next block. cur_addr = vma_end; iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); } } @@ -368,7 +365,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { if (result.IsError()) { for (const auto [unmap_address, unmap_size] : mapped_regions) { ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(), - "MapPhysicalMemory un-map on error"); + "Failed to unmap memory range."); } return result; @@ -381,12 +378,6 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { } ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { - const auto end_addr = target + size; - const auto last_addr = end_addr - 1; - VAddr cur_addr = target; - - ResultCode result = RESULT_SUCCESS; - // Check how much memory is currently mapped. const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size); if (mapped_size_result.Failed()) { @@ -401,13 +392,16 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { // Keep track of the memory regions we unmap. std::vector<std::pair<u64, u64>> unmapped_regions; + ResultCode result = RESULT_SUCCESS; // Try to unmap regions. { - cur_addr = target; + const auto end_addr = target + size; + const auto last_addr = end_addr - 1; + VAddr cur_addr = target; auto iter = FindVMA(target); - ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -434,7 +428,7 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { // Advance to the next block. cur_addr = vma_end; iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); } } @@ -443,10 +437,12 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { if (result.IsError()) { for (const auto [map_address, map_size] : unmapped_regions) { const auto remap_res = - MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size, 0), 0, - map_size, MemoryState::Heap, VMAPermission::None); - ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error"); + MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size), 0, map_size, + MemoryState::Heap, VMAPermission::None); + ASSERT_MSG(remap_res.Succeeded(), "Failed to remap a memory block."); } + + return result; } // Update mapped amount @@ -757,20 +753,26 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre // Always merge allocated memory blocks, even when they don't share the same backing block. if (left.type == VMAType::AllocatedMemoryBlock && (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { + const auto right_begin = right.backing_block->begin() + right.offset; + const auto right_end = right_begin + right.size; + // Check if we can save work. if (left.offset == 0 && left.size == left.backing_block->size()) { // Fast case: left is an entire backing block. - left.backing_block->insert(left.backing_block->end(), - right.backing_block->begin() + right.offset, - right.backing_block->begin() + right.offset + right.size); + left.backing_block->insert(left.backing_block->end(), right_begin, right_end); } else { // Slow case: make a new memory block for left and right. + const auto left_begin = left.backing_block->begin() + left.offset; + const auto left_end = left_begin + left.size; + const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end)); + const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end)); + auto new_memory = std::make_shared<PhysicalMemory>(); - new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset, - left.backing_block->begin() + left.offset + left.size); - new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset, - right.backing_block->begin() + right.offset + right.size); - left.backing_block = new_memory; + new_memory->reserve(left_size + right_size); + new_memory->insert(new_memory->end(), left_begin, left_end); + new_memory->insert(new_memory->end(), right_begin, right_end); + + left.backing_block = std::move(new_memory); left.offset = 0; } @@ -965,7 +967,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address, VAddr cur_addr = address; auto iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -986,7 +988,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address, // Advance to the next block. cur_addr = vma_end; iter = std::next(iter); - ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); + ASSERT(iter != vma_map.end()); } return MakeResult(mapped_size); @@ -1000,7 +1002,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad VAddr cur_addr = address; auto iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -1029,7 +1031,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad // Advance to the next block. cur_addr = vma_end; iter = std::next(iter); - ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); + ASSERT(iter != vma_map.end()); } return MakeResult(mapped_size); diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index b18cde619..850a7ebc3 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -454,8 +454,8 @@ public: /// Maps memory at a given address. /// - /// @param addr The virtual address to map memory at. - /// @param size The amount of memory to map. + /// @param target The virtual address to map memory at. + /// @param size The amount of memory to map. /// /// @note The destination address must lie within the Map region. /// @@ -468,8 +468,8 @@ public: /// Unmaps memory at a given address. /// - /// @param addr The virtual address to unmap memory at. - /// @param size The amount of memory to unmap. + /// @param target The virtual address to unmap memory at. + /// @param size The amount of memory to unmap. /// /// @note The destination address must lie within the Map region. /// diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a192a1f5f..aa2c83937 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -56,7 +56,8 @@ struct LaunchParameters { }; static_assert(sizeof(LaunchParameters) == 0x88); -IWindowController::IWindowController() : ServiceFramework("IWindowController") { +IWindowController::IWindowController(Core::System& system_) + : ServiceFramework("IWindowController"), system{system_} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "CreateWindow"}, @@ -75,7 +76,7 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") { IWindowController::~IWindowController() = default; void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { - const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID(); + const u64 process_id = system.CurrentProcess()->GetProcessID(); LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); @@ -231,8 +232,9 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { IDebugFunctions::~IDebugFunctions() = default; -ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) - : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { +ISelfController::ISelfController(Core::System& system_, + std::shared_ptr<NVFlinger::NVFlinger> nvflinger_) + : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "Exit"}, @@ -280,7 +282,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system_.Kernel(); launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "ISelfController:LaunchableEvent"); @@ -501,8 +503,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable); } -AppletMessageQueue::AppletMessageQueue() { - auto& kernel = Core::System::GetInstance().Kernel(); +AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "AMMessageQueue:OnMessageRecieved"); on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( @@ -937,9 +938,8 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id) - : ServiceFramework("ILibraryAppletCreator"), - current_process_title_id(current_process_title_id) { +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) + : ServiceFramework("ILibraryAppletCreator"), system{system_} { static const FunctionInfo functions[] = { {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, {1, nullptr, "TerminateAllLibraryApplets"}, @@ -961,8 +961,8 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", static_cast<u32>(applet_id), applet_mode); - const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id); + const auto& applet_manager{system.GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id); if (applet == nullptr) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); @@ -999,8 +999,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex const auto handle{rp.Pop<Kernel::Handle>()}; const auto transfer_mem = - Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>( - handle); + system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); if (transfer_mem == nullptr) { LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); @@ -1018,7 +1017,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); } -IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { +IApplicationFunctions::IApplicationFunctions(Core::System& system_) + : ServiceFramework("IApplicationFunctions"), system{system_} { // clang-format off static const FunctionInfo functions[] = { {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, @@ -1057,6 +1057,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, + {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, {500, nullptr, "StartContinuousRecordingFlushForDebug"}, {1000, nullptr, "CreateMovieMaker"}, {1001, nullptr, "PrepareForJit"}, @@ -1064,6 +1065,10 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF // clang-format on RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); } IApplicationFunctions::~IApplicationFunctions() = default; @@ -1175,7 +1180,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { // Get supported languages from NACP, if possible // Default to 0 (all languages supported) u32 supported_languages = 0; - FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()}; + FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; const auto res = pm.GetControlMetadata(); if (res.first != nullptr) { @@ -1183,8 +1188,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { } // Call IApplicationManagerInterface implementation. - auto& service_manager = Core::System::GetInstance().ServiceManager(); - auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2"); + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); auto app_man = ns_am2->GetApplicationManagerInterface(); // Get desired application language @@ -1256,8 +1261,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { "new_journal={:016X}", static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); - FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id, - {new_normal_size, new_journal_size}); + const auto title_id = system.CurrentProcess()->GetTitleID(); + FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size}); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); @@ -1276,8 +1281,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), user_id[1], user_id[0]); - const auto size = - FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id); + const auto title_id = system.CurrentProcess()->GetTitleID(); + const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); @@ -1285,11 +1290,19 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { rb.Push(size.journal); } +void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(gpu_error_detected_event.readable); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { - auto message_queue = std::make_shared<AppletMessageQueue>(); - message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on - // game boot + auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); + // Needed on game boot + message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 6cb582483..28f870302 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -10,12 +10,15 @@ #include "core/hle/kernel/writable_event.h" #include "core/hle/service/service.h" -namespace Service { -namespace NVFlinger { +namespace Kernel { +class KernelCore; +} + +namespace Service::NVFlinger { class NVFlinger; } -namespace AM { +namespace Service::AM { enum SystemLanguage { Japanese = 0, @@ -47,7 +50,7 @@ public: PerformanceModeChanged = 31, }; - AppletMessageQueue(); + explicit AppletMessageQueue(Kernel::KernelCore& kernel); ~AppletMessageQueue(); const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; @@ -65,12 +68,14 @@ private: class IWindowController final : public ServiceFramework<IWindowController> { public: - IWindowController(); + explicit IWindowController(Core::System& system_); ~IWindowController() override; private: void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); void AcquireForegroundRights(Kernel::HLERequestContext& ctx); + + Core::System& system; }; class IAudioController final : public ServiceFramework<IAudioController> { @@ -113,7 +118,8 @@ public: class ISelfController final : public ServiceFramework<ISelfController> { public: - explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); + explicit ISelfController(Core::System& system_, + std::shared_ptr<NVFlinger::NVFlinger> nvflinger_); ~ISelfController() override; private: @@ -208,7 +214,7 @@ private: class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { public: - ILibraryAppletCreator(u64 current_process_title_id); + explicit ILibraryAppletCreator(Core::System& system_); ~ILibraryAppletCreator() override; private: @@ -216,12 +222,12 @@ private: void CreateStorage(Kernel::HLERequestContext& ctx); void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); - u64 current_process_title_id; + Core::System& system; }; class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { public: - IApplicationFunctions(); + explicit IApplicationFunctions(Core::System& system_); ~IApplicationFunctions() override; private: @@ -242,6 +248,10 @@ private: void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); + void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); + + Kernel::EventPair gpu_error_detected_event; + Core::System& system; }; class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { @@ -275,5 +285,4 @@ public: void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); -} // namespace AM -} // namespace Service +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index a34368c8b..e454b77d8 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -50,7 +50,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISelfController>(nvflinger); + rb.PushIpcInterface<ISelfController>(system, nvflinger); } void GetWindowController(Kernel::HLERequestContext& ctx) { @@ -58,7 +58,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IWindowController>(); + rb.PushIpcInterface<IWindowController>(system); } void GetAudioController(Kernel::HLERequestContext& ctx) { @@ -98,7 +98,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); + rb.PushIpcInterface<ILibraryAppletCreator>(system); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -106,7 +106,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationFunctions>(); + rb.PushIpcInterface<IApplicationFunctions>(system); } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; @@ -154,7 +154,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISelfController>(nvflinger); + rb.PushIpcInterface<ISelfController>(system, nvflinger); } void GetWindowController(Kernel::HLERequestContext& ctx) { @@ -162,7 +162,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IWindowController>(); + rb.PushIpcInterface<IWindowController>(system); } void GetAudioController(Kernel::HLERequestContext& ctx) { @@ -194,7 +194,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); + rb.PushIpcInterface<ILibraryAppletCreator>(system); } void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 5d53ef113..a2ffaa440 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -4,7 +4,6 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -64,7 +63,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IWindowController>(); + rb.PushIpcInterface<IWindowController>(system); } void GetSelfController(Kernel::HLERequestContext& ctx) { @@ -72,7 +71,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISelfController>(nvflinger); + rb.PushIpcInterface<ISelfController>(system, nvflinger); } void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { @@ -88,7 +87,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); + rb.PushIpcInterface<ILibraryAppletCreator>(system); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -96,7 +95,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IApplicationFunctions>(); + rb.PushIpcInterface<IApplicationFunctions>(system); } std::shared_ptr<NVFlinger::NVFlinger> nvflinger; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 6bdba2468..d2e35362f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -23,8 +23,7 @@ namespace Service::AM::Applets { -AppletDataBroker::AppletDataBroker() { - auto& kernel = Core::System::GetInstance().Kernel(); +AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { state_changed_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = Kernel::WritableEvent::CreateEventPair( @@ -121,7 +120,7 @@ Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent( return state_changed_event.readable; } -Applet::Applet() = default; +Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} Applet::~Applet() = default; @@ -154,7 +153,7 @@ AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default; AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default; -AppletManager::AppletManager() = default; +AppletManager::AppletManager(Core::System& system_) : system{system_} {} AppletManager::~AppletManager() = default; @@ -216,28 +215,28 @@ void AppletManager::ClearAll() { frontend = {}; } -std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const { +std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { switch (id) { case AppletId::Auth: - return std::make_shared<Auth>(*frontend.parental_controls); + return std::make_shared<Auth>(system, *frontend.parental_controls); case AppletId::Error: - return std::make_shared<Error>(*frontend.error); + return std::make_shared<Error>(system, *frontend.error); case AppletId::ProfileSelect: - return std::make_shared<ProfileSelect>(*frontend.profile_select); + return std::make_shared<ProfileSelect>(system, *frontend.profile_select); case AppletId::SoftwareKeyboard: - return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard); + return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); case AppletId::PhotoViewer: - return std::make_shared<PhotoViewer>(*frontend.photo_viewer); + return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); case AppletId::LibAppletShop: - return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id, + return std::make_shared<WebBrowser>(system, *frontend.web_browser, frontend.e_commerce.get()); case AppletId::LibAppletOff: - return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id); + return std::make_shared<WebBrowser>(system, *frontend.web_browser); default: UNIMPLEMENTED_MSG( "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", static_cast<u8>(id)); - return std::make_shared<StubApplet>(id); + return std::make_shared<StubApplet>(system, id); } } diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index adc973dad..764c3418c 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -12,6 +12,10 @@ union ResultCode; +namespace Core { +class System; +} + namespace Core::Frontend { class ECommerceApplet; class ErrorApplet; @@ -22,6 +26,10 @@ class SoftwareKeyboardApplet; class WebBrowserApplet; } // namespace Core::Frontend +namespace Kernel { +class KernelCore; +} + namespace Service::AM { class IStorage; @@ -53,7 +61,7 @@ enum class AppletId : u32 { class AppletDataBroker final { public: - AppletDataBroker(); + explicit AppletDataBroker(Kernel::KernelCore& kernel_); ~AppletDataBroker(); struct RawChannelData { @@ -108,7 +116,7 @@ private: class Applet { public: - Applet(); + explicit Applet(Kernel::KernelCore& kernel_); virtual ~Applet(); virtual void Initialize(); @@ -179,7 +187,7 @@ struct AppletFrontendSet { class AppletManager { public: - AppletManager(); + explicit AppletManager(Core::System& system_); ~AppletManager(); void SetAppletFrontendSet(AppletFrontendSet set); @@ -187,10 +195,11 @@ public: void SetDefaultAppletsIfMissing(); void ClearAll(); - std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const; + std::shared_ptr<Applet> GetApplet(AppletId id) const; private: AppletFrontendSet frontend; + Core::System& system; }; } // namespace Applets diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index af3a900f8..a7db26725 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -85,7 +85,8 @@ ResultCode Decode64BitError(u64 error) { } // Anonymous namespace -Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {} +Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} Error::~Error() = default; @@ -145,8 +146,8 @@ void Error::Execute() { } const auto callback = [this] { DisplayCompleted(); }; - const auto title_id = Core::CurrentProcess()->GetTitleID(); - const auto& reporter{Core::System::GetInstance().GetReporter()}; + const auto title_id = system.CurrentProcess()->GetTitleID(); + const auto& reporter{system.GetReporter()}; switch (mode) { case ErrorAppletMode::ShowError: diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h index a3590d181..a105cdb0c 100644 --- a/src/core/hle/service/am/applets/error.h +++ b/src/core/hle/service/am/applets/error.h @@ -7,6 +7,10 @@ #include "core/hle/result.h" #include "core/hle/service/am/applets/applets.h" +namespace Core { +class System; +} + namespace Service::AM::Applets { enum class ErrorAppletMode : u8 { @@ -21,7 +25,7 @@ enum class ErrorAppletMode : u8 { class Error final : public Applet { public: - explicit Error(const Core::Frontend::ErrorApplet& frontend); + explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_); ~Error() override; void Initialize() override; @@ -42,6 +46,7 @@ private: std::unique_ptr<ErrorArguments> args; bool complete = false; + Core::System& system; }; } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index e0def8dff..328438a1d 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -37,7 +37,8 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) } } -Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {} +Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_) {} Auth::~Auth() = default; @@ -151,7 +152,8 @@ void Auth::AuthFinished(bool successful) { broker.SignalStateChanged(); } -PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} +PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} PhotoViewer::~PhotoViewer() = default; @@ -185,7 +187,7 @@ void PhotoViewer::Execute() { const auto callback = [this] { ViewFinished(); }; switch (mode) { case PhotoViewerAppletMode::CurrentApp: - frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback); + frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback); break; case PhotoViewerAppletMode::AllApps: frontend.ShowAllPhotos(callback); @@ -200,7 +202,8 @@ void PhotoViewer::ViewFinished() { broker.SignalStateChanged(); } -StubApplet::StubApplet(AppletId id) : id(id) {} +StubApplet::StubApplet(Core::System& system_, AppletId id_) + : Applet{system_.Kernel()}, id(id_), system{system_} {} StubApplet::~StubApplet() = default; @@ -209,7 +212,7 @@ void StubApplet::Initialize() { Applet::Initialize(); const auto data = broker.PeekDataToAppletForDebug(); - Core::System::GetInstance().GetReporter().SaveUnimplementedAppletReport( + system.GetReporter().SaveUnimplementedAppletReport( static_cast<u32>(id), common_args.arguments_version, common_args.library_version, common_args.theme_color, common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive); diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index 0da252044..cfa2df369 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h @@ -6,6 +6,10 @@ #include "core/hle/service/am/applets/applets.h" +namespace Core { +class System; +} + namespace Service::AM::Applets { enum class AuthAppletType : u32 { @@ -16,7 +20,7 @@ enum class AuthAppletType : u32 { class Auth final : public Applet { public: - explicit Auth(Core::Frontend::ParentalControlsApplet& frontend); + explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_); ~Auth() override; void Initialize() override; @@ -45,7 +49,7 @@ enum class PhotoViewerAppletMode : u8 { class PhotoViewer final : public Applet { public: - explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend); + explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_); ~PhotoViewer() override; void Initialize() override; @@ -60,11 +64,12 @@ private: const Core::Frontend::PhotoViewerApplet& frontend; bool complete = false; PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; + Core::System& system; }; class StubApplet final : public Applet { public: - explicit StubApplet(AppletId id); + explicit StubApplet(Core::System& system_, AppletId id_); ~StubApplet() override; void Initialize() override; @@ -76,6 +81,7 @@ public: private: AppletId id; + Core::System& system; }; } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 57b5419e8..3eba696ca 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -15,8 +15,9 @@ namespace Service::AM::Applets { constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; -ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend) - : frontend(frontend) {} +ProfileSelect::ProfileSelect(Core::System& system_, + const Core::Frontend::ProfileSelectApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_) {} ProfileSelect::~ProfileSelect() = default; diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index 563cd744a..16364ead7 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h @@ -11,6 +11,10 @@ #include "core/hle/result.h" #include "core/hle/service/am/applets/applets.h" +namespace Core { +class System; +} + namespace Service::AM::Applets { struct UserSelectionConfig { @@ -29,7 +33,8 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco class ProfileSelect final : public Applet { public: - explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend); + explicit ProfileSelect(Core::System& system_, + const Core::Frontend::ProfileSelectApplet& frontend_); ~ProfileSelect() override; void Initialize() override; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index e197990f7..748559cd0 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -39,8 +39,9 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( return params; } -SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend) - : frontend(frontend) {} +SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, + const Core::Frontend::SoftwareKeyboardApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_) {} SoftwareKeyboard::~SoftwareKeyboard() = default; diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 0fbc43e51..ef4801fc6 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -16,6 +16,10 @@ union ResultCode; +namespace Core { +class System; +} + namespace Service::AM::Applets { enum class KeysetDisable : u32 { @@ -55,7 +59,8 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz class SoftwareKeyboard final : public Applet { public: - explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend); + explicit SoftwareKeyboard(Core::System& system_, + const Core::Frontend::SoftwareKeyboardApplet& frontend_); ~SoftwareKeyboard() override; void Initialize() override; diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index f3c9fef0e..32283e819 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -190,8 +190,9 @@ std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& return out; } -FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) { - const auto& installed{Core::System::GetInstance().GetContentProvider()}; +FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id, + FileSys::ContentRecordType type) { + const auto& installed{system.GetContentProvider()}; const auto res = installed.GetEntry(title_id, type); if (res != nullptr) { @@ -207,10 +208,10 @@ FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordTyp } // Anonymous namespace -WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, - Core::Frontend::ECommerceApplet* frontend_e_commerce) - : frontend(frontend), frontend_e_commerce(frontend_e_commerce), - current_process_title_id(current_process_title_id) {} +WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, + Core::Frontend::ECommerceApplet* frontend_e_commerce_) + : Applet{system_.Kernel()}, frontend(frontend_), + frontend_e_commerce(frontend_e_commerce_), system{system_} {} WebBrowser::~WebBrowser() = default; @@ -266,7 +267,7 @@ void WebBrowser::UnpackRomFS() { ASSERT(offline_romfs != nullptr); const auto dir = FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); - const auto& vfs{Core::System::GetInstance().GetFilesystem()}; + const auto& vfs{system.GetFilesystem()}; const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); FileSys::VfsRawCopyD(dir, temp_dir); @@ -470,10 +471,10 @@ void WebBrowser::InitializeOffline() { } if (title_id == 0) { - title_id = current_process_title_id; + title_id = system.CurrentProcess()->GetTitleID(); } - offline_romfs = GetApplicationRomFS(title_id, type); + offline_romfs = GetApplicationRomFS(system, title_id, type); if (offline_romfs == nullptr) { status = ResultCode(-1); LOG_ERROR(Service_AM, "Failed to find offline data for request!"); diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 870f57b64..8d4027411 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -9,6 +9,10 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" +namespace Core { +class System; +} + namespace Service::AM::Applets { enum class ShimKind : u32; @@ -17,8 +21,8 @@ enum class WebArgTLVType : u16; class WebBrowser final : public Applet { public: - WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, - Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr); + WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, + Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr); ~WebBrowser() override; @@ -59,8 +63,6 @@ private: bool unpacked = false; ResultCode status = RESULT_SUCCESS; - u64 current_process_title_id; - ShimKind kind; std::map<WebArgTLVType, std::vector<u8>> args; @@ -74,6 +76,8 @@ private: std::optional<u128> user_id; std::optional<bool> shop_full_display; std::string shop_extra_parameter; + + Core::System& system; }; } // namespace Service::AM::Applets diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 5b0b7f17e..f162249ed 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -165,15 +165,15 @@ public: static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, - {2, nullptr, "GetAudioDeviceOutputVolume"}, + {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"}, {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"}, {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, - {8, nullptr, "GetAudioDeviceOutputVolumeAuto"}, + {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"}, {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, - {11, nullptr, "QueryAudioDeviceInputEvent"}, + {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"}, {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"}, {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, }; @@ -183,6 +183,10 @@ public: buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IAudioOutBufferReleasedEvent"); + // Should be similar to audio_output_device_switch_event + audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioInputDeviceSwitchedEvent"); + // Should only be signalled when an audio output device has been changed, example: speaker // to headset audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair( @@ -246,6 +250,19 @@ private: rb.Push(RESULT_SUCCESS); } + void GetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto device_name_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(device_name_buffer); + + LOG_WARNING(Service_Audio, "(STUBBED) called. name={}", name); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(1.0f); + } + void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); @@ -279,6 +296,15 @@ private: rb.Push<u32>(1); } + // Should be similar to QueryAudioDeviceOutputEvent + void QueryAudioDeviceInputEvent(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_Audio, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(audio_input_device_switch_event.readable); + } + void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); @@ -289,6 +315,7 @@ private: u32_le revision = 0; Kernel::EventPair buffer_event; + Kernel::EventPair audio_input_device_switch_event; Kernel::EventPair audio_output_device_switch_event; }; // namespace Audio diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index 6701cb913..af70d174d 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -2,32 +2,37 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/crypto/key_manager.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/service/service.h" namespace Service::ES { +constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::ETicket, 2}; +constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3}; + class ETicket final : public ServiceFramework<ETicket> { public: explicit ETicket() : ServiceFramework{"es"} { // clang-format off static const FunctionInfo functions[] = { - {1, nullptr, "ImportTicket"}, + {1, &ETicket::ImportTicket, "ImportTicket"}, {2, nullptr, "ImportTicketCertificateSet"}, {3, nullptr, "DeleteTicket"}, {4, nullptr, "DeletePersonalizedTicket"}, {5, nullptr, "DeleteAllCommonTicket"}, {6, nullptr, "DeleteAllPersonalizedTicket"}, {7, nullptr, "DeleteAllPersonalizedTicketEx"}, - {8, nullptr, "GetTitleKey"}, - {9, nullptr, "CountCommonTicket"}, - {10, nullptr, "CountPersonalizedTicket"}, - {11, nullptr, "ListCommonTicket"}, - {12, nullptr, "ListPersonalizedTicket"}, + {8, &ETicket::GetTitleKey, "GetTitleKey"}, + {9, &ETicket::CountCommonTicket, "CountCommonTicket"}, + {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"}, + {11, &ETicket::ListCommonTicket, "ListCommonTicket"}, + {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"}, {13, nullptr, "ListMissingPersonalizedTicket"}, - {14, nullptr, "GetCommonTicketSize"}, - {15, nullptr, "GetPersonalizedTicketSize"}, - {16, nullptr, "GetCommonTicketData"}, - {17, nullptr, "GetPersonalizedTicketData"}, + {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"}, + {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"}, + {16, &ETicket::GetCommonTicketData, "GetCommonTicketData"}, + {17, &ETicket::GetPersonalizedTicketData, "GetPersonalizedTicketData"}, {18, nullptr, "OwnTicket"}, {19, nullptr, "GetTicketInfo"}, {20, nullptr, "ListLightTicketInfo"}, @@ -51,7 +56,212 @@ public: }; // clang-format on RegisterHandlers(functions); + + keys.PopulateTickets(); + keys.SynthesizeTickets(); + } + +private: + bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) { + if (rights_id == u128{}) { + LOG_ERROR(Service_ETicket, "The rights ID was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_RIGHTS_ID); + return false; + } + + return true; + } + + void ImportTicket(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto ticket = ctx.ReadBuffer(); + const auto cert = ctx.ReadBuffer(1); + + if (ticket.size() < sizeof(Core::Crypto::Ticket)) { + LOG_ERROR(Service_ETicket, "The input buffer is not large enough!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + Core::Crypto::Ticket raw{}; + std::memcpy(&raw, ticket.data(), sizeof(Core::Crypto::Ticket)); + + if (!keys.AddTicketPersonalized(raw)) { + LOG_ERROR(Service_ETicket, "The ticket could not be imported!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void GetTitleKey(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto key = + keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); + + if (key == Core::Crypto::Key128{}) { + LOG_ERROR(Service_ETicket, + "The titlekey doesn't exist in the KeyManager or the rights ID was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_RIGHTS_ID); + return; + } + + ctx.WriteBuffer(key.data(), key.size()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void CountCommonTicket(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ETicket, "called"); + + const auto count = keys.GetCommonTickets().size(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(count); + } + + void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ETicket, "called"); + + const auto count = keys.GetPersonalizedTickets().size(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(count); + } + + void ListCommonTicket(Kernel::HLERequestContext& ctx) { + u32 out_entries; + if (keys.GetCommonTickets().empty()) + out_entries = 0; + else + out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + + LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); + + keys.PopulateTickets(); + const auto tickets = keys.GetCommonTickets(); + std::vector<u128> ids; + std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), + [](const auto& pair) { return pair.first; }); + + out_entries = std::min<u32>(ids.size(), out_entries); + ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(out_entries); } + + void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) { + u32 out_entries; + if (keys.GetPersonalizedTickets().empty()) + out_entries = 0; + else + out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + + LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); + + keys.PopulateTickets(); + const auto tickets = keys.GetPersonalizedTickets(); + std::vector<u128> ids; + std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), + [](const auto& pair) { return pair.first; }); + + out_entries = std::min<u32>(ids.size(), out_entries); + ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(out_entries); + } + + void GetCommonTicketSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetCommonTickets().at(rights_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(ticket.GetSize()); + } + + void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetPersonalizedTickets().at(rights_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(ticket.GetSize()); + } + + void GetCommonTicketData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetCommonTickets().at(rights_id); + + const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize()); + ctx.WriteBuffer(&ticket, write_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(write_size); + } + + void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetPersonalizedTickets().at(rights_id); + + const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize()); + ctx.WriteBuffer(&ticket, write_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(write_size); + } + + Core::Crypto::KeyManager keys; }; void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index fe49c2161..01fa06ad3 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -5,7 +5,7 @@ #include <array> #include <cstring> #include <ctime> -#include <fmt/time.h> +#include <fmt/chrono.h> #include "common/file_util.h" #include "common/logging/log.h" #include "common/scm_rev.h" diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 1e81f776f..e47fe8188 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -636,10 +636,15 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { return LedPattern{0, 0, 0, 0}; }; } + void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { can_controllers_vibrate = can_vibrate; } +bool Controller_NPad::IsVibrationEnabled() const { + return can_controllers_vibrate; +} + void Controller_NPad::ClearAllConnectedControllers() { for (auto& controller : connected_controllers) { if (controller.is_connected && controller.type != NPadControllerType::None) { @@ -648,6 +653,7 @@ void Controller_NPad::ClearAllConnectedControllers() { } } } + void Controller_NPad::DisconnectAllConnectedControllers() { std::for_each(connected_controllers.begin(), connected_controllers.end(), [](ControllerHolder& controller) { controller.is_connected = false; }); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4b6c1083f..f28b36806 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -119,6 +119,7 @@ public: void DisconnectNPad(u32 npad_id); LedPattern GetLedPattern(u32 npad_id); void SetVibrationEnabled(bool can_vibrate); + bool IsVibrationEnabled() const; void ClearAllConnectedControllers(); void DisconnectAllConnectedControllers(); void ConnectAllDisconnectedControllers(); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 0bd24b8eb..f8b1ca816 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -216,8 +216,8 @@ Hid::Hid() : ServiceFramework("hid") { {201, &Hid::SendVibrationValue, "SendVibrationValue"}, {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, - {204, nullptr, "PermitVibration"}, - {205, nullptr, "IsVibrationPermitted"}, + {204, &Hid::PermitVibration, "PermitVibration"}, + {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"}, {206, &Hid::SendVibrationValues, "SendVibrationValues"}, {207, nullptr, "SendVibrationGcErmCommand"}, {208, nullptr, "GetActualVibrationGcErmCommand"}, @@ -679,6 +679,27 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { rb.PushIpcInterface<IActiveVibrationDeviceList>(); } +void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto can_vibrate{rp.Pop<bool>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetVibrationEnabled(can_vibrate); + + LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push( + applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled()); +} + void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 28260ef1b..2fd6d9fc7 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -114,6 +114,8 @@ private: void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); + void PermitVibration(Kernel::HLERequestContext& ctx); + void IsVibrationPermitted(Kernel::HLERequestContext& ctx); void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); void StopSixAxisSensor(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 131b01d62..8d0353075 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -175,6 +175,10 @@ MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) { } // namespace std::ostream& operator<<(std::ostream& os, Source source) { + if (static_cast<std::size_t>(source) >= SOURCE_NAMES.size()) { + return os << "[UNKNOWN SOURCE]"; + } + os << SOURCE_NAMES.at(static_cast<std::size_t>(source)); return os; } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 76494f0b7..926a1285d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -37,7 +37,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 transform, crop_rect}; system.GetPerfStats().EndGameFrame(); - system.GPU().SwapBuffers(framebuffer); + system.GPU().SwapBuffers(&framebuffer); } } // namespace Service::Nvidia::Devices diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 5d4c3e6ea..cfe0771e2 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -5,8 +5,8 @@ #include <ctime> #include <fstream> +#include <fmt/chrono.h> #include <fmt/format.h> -#include <fmt/time.h> #include <json.hpp> #include "common/file_util.h" |