diff options
Diffstat (limited to 'src/core')
66 files changed, 1219 insertions, 557 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b96ca9374..d0c405ec7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -126,6 +126,8 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/controller.cpp + frontend/applets/controller.h frontend/applets/error.cpp frontend/applets/error.h frontend/applets/general_frontend.cpp @@ -244,6 +246,8 @@ add_library(core STATIC hle/service/am/applet_oe.h hle/service/am/applets/applets.cpp hle/service/am/applets/applets.h + hle/service/am/applets/controller.cpp + hle/service/am/applets/controller.h hle/service/am/applets/error.cpp hle/service/am/applets/error.h hle/service/am/applets/general_backend.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 7356d252e..dc6f4af3a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -35,8 +35,8 @@ public: std::optional<u8> option) override; ARM_Dynarmic_32& parent; - u32 uprw; - u32 uro; + u32 uprw = 0; + u32 uro = 0; }; } // namespace Core diff --git a/src/core/core.cpp b/src/core/core.cpp index df81e8e2c..81e8cc338 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -178,7 +178,7 @@ struct System::Impl { arp_manager.ResetAll(); telemetry_session = std::make_unique<Core::TelemetrySession>(); - service_manager = std::make_shared<Service::SM::ServiceManager>(); + service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); Service::Init(service_manager, system); GDBStub::DeferStart(); @@ -221,7 +221,7 @@ struct System::Impl { telemetry_session->AddInitialInfo(*app_loader); auto main_process = Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); - const auto [load_result, load_parameters] = app_loader->Load(*main_process); + const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); Shutdown(); @@ -629,11 +629,11 @@ Loader::AppLoader& System::GetAppLoader() const { return *impl->app_loader; } -void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) { +void System::SetFilesystem(FileSys::VirtualFilesystem vfs) { impl->virtual_filesystem = std::move(vfs); } -std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const { +FileSys::VirtualFilesystem System::GetFilesystem() const { return impl->virtual_filesystem; } diff --git a/src/core/core.h b/src/core/core.h index 5c6cfbffe..83ded63a5 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -316,9 +316,9 @@ public: Service::SM::ServiceManager& ServiceManager(); const Service::SM::ServiceManager& ServiceManager() const; - void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs); + void SetFilesystem(FileSys::VirtualFilesystem vfs); - std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; + FileSys::VirtualFilesystem GetFilesystem() const; void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, const std::array<u8, 0x20>& build_id, VAddr main_region_begin, diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index dc591c730..65d246050 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -23,7 +23,6 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "core/core.h" #include "core/crypto/aes_util.h" #include "core/crypto/key_manager.h" #include "core/crypto/partition_data_manager.h" @@ -1022,10 +1021,10 @@ void KeyManager::DeriveBase() { } } -void KeyManager::DeriveETicket(PartitionDataManager& data) { +void KeyManager::DeriveETicket(PartitionDataManager& data, + const FileSys::ContentProvider& provider) { // ETicket keys - const auto es = Core::System::GetInstance().GetContentProvider().GetEntry( - 0x0100000000000033, FileSys::ContentRecordType::Program); + const auto es = provider.GetEntry(0x0100000000000033, FileSys::ContentRecordType::Program); if (es == nullptr) { return; diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 321b75323..0a7220286 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -20,6 +20,10 @@ namespace Common::FS { class IOFile; } +namespace FileSys { +class ContentProvider; +} + namespace Loader { enum class ResultStatus : u16; } @@ -252,7 +256,7 @@ public: bool BaseDeriveNecessary() const; void DeriveBase(); - void DeriveETicket(PartitionDataManager& data); + void DeriveETicket(PartitionDataManager& data, const FileSys::ContentProvider& provider); void PopulateTickets(); void SynthesizeTickets(); diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index e04a54c3c..7c6304ff0 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -4,10 +4,10 @@ #include <fmt/format.h> #include "common/file_util.h" -#include "core/core.h" #include "core/file_sys/bis_factory.h" #include "core/file_sys/mode.h" #include "core/file_sys/registered_cache.h" +#include "core/file_sys/vfs.h" namespace FileSys { @@ -81,11 +81,11 @@ VirtualDir BISFactory::OpenPartition(BisPartitionId id) const { } } -VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const { +VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id, + VirtualFilesystem file_system) const { auto& keys = Core::Crypto::KeyManager::Instance(); - Core::Crypto::PartitionDataManager pdm{ - Core::System::GetInstance().GetFilesystem()->OpenDirectory( - Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)}; + Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory( + Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)}; keys.PopulateFromPartitionData(pdm); switch (id) { diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index 438d3f8d8..136485881 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h @@ -52,7 +52,7 @@ public: VirtualDir GetModificationDumpRoot(u64 title_id) const; VirtualDir OpenPartition(BisPartitionId id) const; - VirtualFile OpenPartitionStorage(BisPartitionId id) const; + VirtualFile OpenPartitionStorage(BisPartitionId id, VirtualFilesystem file_system) const; VirtualDir GetImageDirectory() const; diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 9ab86e35b..403c4219a 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -83,7 +83,7 @@ enum class Language : u8 { Italian = 7, Dutch = 8, CanadianFrench = 9, - Portugese = 10, + Portuguese = 10, Russian = 11, Korean = 12, Taiwanese = 13, diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp index fe7375e84..5990a2fd5 100644 --- a/src/core/file_sys/nca_patch.cpp +++ b/src/core/file_sys/nca_patch.cpp @@ -12,6 +12,49 @@ #include "core/file_sys/nca_patch.h" namespace FileSys { +namespace { +template <bool Subsection, typename BlockType, typename BucketType> +std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockType& block, + const BucketType& buckets) { + if constexpr (Subsection) { + const auto& last_bucket = buckets[block.number_buckets - 1]; + if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) { + return {block.number_buckets - 1, last_bucket.number_entries}; + } + } else { + ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block."); + } + + std::size_t bucket_id = std::count_if( + block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets, + [&offset](u64 base_offset) { return base_offset <= offset; }); + + const auto& bucket = buckets[bucket_id]; + + if (bucket.number_entries == 1) { + return {bucket_id, 0}; + } + + std::size_t low = 0; + std::size_t mid = 0; + std::size_t high = bucket.number_entries - 1; + while (low <= high) { + mid = (low + high) / 2; + if (bucket.entries[mid].address_patch > offset) { + high = mid - 1; + } else { + if (mid == bucket.number_entries - 1 || + bucket.entries[mid + 1].address_patch > offset) { + return {bucket_id, mid}; + } + + low = mid + 1; + } + } + + UNREACHABLE_MSG("Offset could not be found in BKTR block."); +} +} // Anonymous namespace BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock relocation_, std::vector<RelocationBucket> relocation_buckets_, SubsectionBlock subsection_, @@ -110,46 +153,6 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const { return raw_read; } -template <bool Subsection, typename BlockType, typename BucketType> -std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block, - BucketType buckets) const { - if constexpr (Subsection) { - const auto last_bucket = buckets[block.number_buckets - 1]; - if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) - return {block.number_buckets - 1, last_bucket.number_entries}; - } else { - ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block."); - } - - std::size_t bucket_id = std::count_if( - block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets, - [&offset](u64 base_offset) { return base_offset <= offset; }); - - const auto bucket = buckets[bucket_id]; - - if (bucket.number_entries == 1) - return {bucket_id, 0}; - - std::size_t low = 0; - std::size_t mid = 0; - std::size_t high = bucket.number_entries - 1; - while (low <= high) { - mid = (low + high) / 2; - if (bucket.entries[mid].address_patch > offset) { - high = mid - 1; - } else { - if (mid == bucket.number_entries - 1 || - bucket.entries[mid + 1].address_patch > offset) { - return {bucket_id, mid}; - } - - low = mid + 1; - } - } - - UNREACHABLE_MSG("Offset could not be found in BKTR block."); -} - RelocationEntry BKTR::GetRelocationEntry(u64 offset) const { const auto res = SearchBucketEntry<false>(offset, relocation, relocation_buckets); return relocation_buckets[res.first].entries[res.second]; diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h index 8e64e8378..60c544f8e 100644 --- a/src/core/file_sys/nca_patch.h +++ b/src/core/file_sys/nca_patch.h @@ -117,10 +117,6 @@ public: bool Rename(std::string_view name) override; private: - template <bool Subsection, typename BlockType, typename BucketType> - std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block, - BucketType buckets) const; - RelocationEntry GetRelocationEntry(u64 offset) const; RelocationEntry GetNextRelocationEntry(u64 offset) const; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index c228d253e..b9c09b456 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -27,6 +27,7 @@ #include "core/settings.h" namespace FileSys { +namespace { constexpr u64 SINGLE_BYTE_MODULUS = 0x100; constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; @@ -36,19 +37,28 @@ constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", }; -std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { +enum class TitleVersionFormat : u8 { + ThreeElements, ///< vX.Y.Z + FourElements, ///< vX.Y.Z.W +}; + +std::string FormatTitleVersion(u32 version, + TitleVersionFormat format = TitleVersionFormat::ThreeElements) { std::array<u8, sizeof(u32)> bytes{}; - bytes[0] = version % SINGLE_BYTE_MODULUS; + bytes[0] = static_cast<u8>(version % SINGLE_BYTE_MODULUS); for (std::size_t i = 1; i < bytes.size(); ++i) { version /= SINGLE_BYTE_MODULUS; - bytes[i] = version % SINGLE_BYTE_MODULUS; + bytes[i] = static_cast<u8>(version % SINGLE_BYTE_MODULUS); } - if (format == TitleVersionFormat::FourElements) + if (format == TitleVersionFormat::FourElements) { return fmt::format("v{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); + } return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]); } +// Returns a directory with name matching name case-insensitive. Returns nullptr if directory +// doesn't have a directory with name. VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) { #ifdef _WIN32 return dir->GetSubdirectory(name); @@ -65,6 +75,43 @@ VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) #endif } +std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder( + u64 title_id, const PatchManager::BuildID& build_id_, const VirtualDir& base_path, bool upper) { + const auto build_id_raw = Common::HexToString(build_id_, upper); + const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2); + const auto file = base_path->GetFile(fmt::format("{}.txt", build_id)); + + if (file == nullptr) { + LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}", + title_id, build_id); + return std::nullopt; + } + + std::vector<u8> data(file->GetSize()); + if (file->Read(data.data(), data.size()) != data.size()) { + LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}", + title_id, build_id); + return std::nullopt; + } + + const Core::Memory::TextCheatParser parser; + return parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size())); +} + +void AppendCommaIfNotEmpty(std::string& to, std::string_view with) { + if (to.empty()) { + to += with; + } else { + to += ", "; + to += with; + } +} + +bool IsDirValidAndNonEmpty(const VirtualDir& dir) { + return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty()); +} +} // Anonymous namespace + PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} PatchManager::~PatchManager() = default; @@ -245,7 +292,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st return out; } -bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const { +bool PatchManager::HasNSOPatch(const BuildID& build_id_) const { const auto build_id_raw = Common::HexToString(build_id_); const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); @@ -265,36 +312,8 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const { return !CollectPatches(patch_dirs, build_id).empty(); } -namespace { -std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder( - const Core::System& system, u64 title_id, const std::array<u8, 0x20>& build_id_, - const VirtualDir& base_path, bool upper) { - const auto build_id_raw = Common::HexToString(build_id_, upper); - const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2); - const auto file = base_path->GetFile(fmt::format("{}.txt", build_id)); - - if (file == nullptr) { - LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}", - title_id, build_id); - return std::nullopt; - } - - std::vector<u8> data(file->GetSize()); - if (file->Read(data.data(), data.size()) != data.size()) { - LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}", - title_id, build_id); - return std::nullopt; - } - - Core::Memory::TextCheatParser parser; - return parser.Parse(system, - std::string_view(reinterpret_cast<const char*>(data.data()), data.size())); -} - -} // Anonymous namespace - std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( - const Core::System& system, const std::array<u8, 32>& build_id_) const { + const Core::System& system, const BuildID& build_id_) const { const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); if (load_dir == nullptr) { LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); @@ -314,14 +333,12 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); if (cheats_dir != nullptr) { - auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true); - if (res.has_value()) { + if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) { std::copy(res->begin(), res->end(), std::back_inserter(out)); continue; } - res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, false); - if (res.has_value()) { + if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) { std::copy(res->begin(), res->end(), std::back_inserter(out)); } } @@ -435,21 +452,11 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content return romfs; } -static void AppendCommaIfNotEmpty(std::string& to, const std::string& with) { - if (to.empty()) - to += with; - else - to += ", " + with; -} - -static bool IsDirValidAndNonEmpty(const VirtualDir& dir) { - return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty()); -} - -std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames( - VirtualFile update_raw) const { - if (title_id == 0) +PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile update_raw) const { + if (title_id == 0) { return {}; + } + std::map<std::string, std::string, std::less<>> out; const auto& installed = Core::System::GetInstance().GetContentProvider(); const auto& disabled = Settings::values.disabled_addons[title_id]; @@ -472,8 +479,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam if (meta_ver.value_or(0) == 0) { out.insert_or_assign(update_label, ""); } else { - out.insert_or_assign( - update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements)); + out.insert_or_assign(update_label, FormatTitleVersion(*meta_ver)); } } else if (update_raw != nullptr) { out.insert_or_assign(update_label, "PACKED"); @@ -562,40 +568,46 @@ std::optional<u32> PatchManager::GetGameVersion() const { return installed.GetEntryVersion(title_id); } -std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { +PatchManager::Metadata PatchManager::GetControlMetadata() const { const auto& installed = Core::System::GetInstance().GetContentProvider(); const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control); - if (base_control_nca == nullptr) + if (base_control_nca == nullptr) { return {}; + } return ParseControlNCA(*base_control_nca); } -std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(const NCA& nca) const { +PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const { const auto base_romfs = nca.GetRomFS(); - if (base_romfs == nullptr) + if (base_romfs == nullptr) { return {}; + } const auto romfs = PatchRomFS(base_romfs, nca.GetBaseIVFCOffset(), ContentRecordType::Control); - if (romfs == nullptr) + if (romfs == nullptr) { return {}; + } const auto extracted = ExtractRomFS(romfs); - if (extracted == nullptr) + if (extracted == nullptr) { return {}; + } auto nacp_file = extracted->GetFile("control.nacp"); - if (nacp_file == nullptr) + if (nacp_file == nullptr) { nacp_file = extracted->GetFile("Control.nacp"); + } auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file); VirtualFile icon_file; for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat"); - if (icon_file != nullptr) + icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat")); + if (icon_file != nullptr) { break; + } } return {std::move(nacp), icon_file}; diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 532f4995f..1f28c6241 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -22,70 +22,62 @@ namespace FileSys { class NCA; class NACP; -enum class TitleVersionFormat : u8 { - ThreeElements, ///< vX.Y.Z - FourElements, ///< vX.Y.Z.W -}; - -std::string FormatTitleVersion(u32 version, - TitleVersionFormat format = TitleVersionFormat::ThreeElements); - -// Returns a directory with name matching name case-insensitive. Returns nullptr if directory -// doesn't have a directory with name. -VirtualDir FindSubdirectoryCaseless(VirtualDir dir, std::string_view name); - // A centralized class to manage patches to games. class PatchManager { public: + using BuildID = std::array<u8, 0x20>; + using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; + using PatchVersionNames = std::map<std::string, std::string, std::less<>>; + explicit PatchManager(u64 title_id); ~PatchManager(); - u64 GetTitleID() const; + [[nodiscard]] u64 GetTitleID() const; // Currently tracked ExeFS patches: // - Game Updates - VirtualDir PatchExeFS(VirtualDir exefs) const; + [[nodiscard]] VirtualDir PatchExeFS(VirtualDir exefs) const; // Currently tracked NSO patches: // - IPS // - IPSwitch - std::vector<u8> PatchNSO(const std::vector<u8>& nso, const std::string& name) const; + [[nodiscard]] std::vector<u8> PatchNSO(const std::vector<u8>& nso, + const std::string& name) const; // Checks to see if PatchNSO() will have any effect given the NSO's build ID. // Used to prevent expensive copies in NSO loader. - bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const; + [[nodiscard]] bool HasNSOPatch(const BuildID& build_id) const; // Creates a CheatList object with all - std::vector<Core::Memory::CheatEntry> CreateCheatList( - const Core::System& system, const std::array<u8, 0x20>& build_id) const; + [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( + const Core::System& system, const BuildID& build_id) const; // Currently tracked RomFS patches: // - Game Updates // - LayeredFS - VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset, - ContentRecordType type = ContentRecordType::Program, - VirtualFile update_raw = nullptr) const; + [[nodiscard]] VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset, + ContentRecordType type = ContentRecordType::Program, + VirtualFile update_raw = nullptr) const; // Returns a vector of pairs between patch names and patch versions. // i.e. Update 3.2.2 will return {"Update", "3.2.2"} - std::map<std::string, std::string, std::less<>> GetPatchVersionNames( - VirtualFile update_raw = nullptr) const; + [[nodiscard]] PatchVersionNames GetPatchVersionNames(VirtualFile update_raw = nullptr) const; // If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails, // it will fallback to the Meta-type NCA of the base game. If that fails, the result will be // std::nullopt - std::optional<u32> GetGameVersion() const; + [[nodiscard]] std::optional<u32> GetGameVersion() const; // Given title_id of the program, attempts to get the control data of the update and parse // it, falling back to the base control data. - std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const; + [[nodiscard]] Metadata GetControlMetadata() const; // Version of GetControlMetadata that takes an arbitrary NCA - std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const; + [[nodiscard]] Metadata ParseControlNCA(const NCA& nca) const; private: - std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs, - const std::string& build_id) const; + [[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs, + const std::string& build_id) const; u64 title_id; }; diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 418a39a7e..e967a254e 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -6,7 +6,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "core/core.h" #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" @@ -19,7 +18,9 @@ namespace FileSys { -RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) { +RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider, + Service::FileSystem::FileSystemController& controller) + : content_provider{provider}, filesystem_controller{controller} { // Load the RomFS from the app if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) { LOG_ERROR(Service_FS, "Unable to read RomFS!"); @@ -46,39 +47,38 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) const { - std::shared_ptr<NCA> res; - - switch (storage) { - case StorageId::None: - res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type); - break; - case StorageId::NandSystem: - res = - Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry( - title_id, type); - break; - case StorageId::NandUser: - res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry( - title_id, type); - break; - case StorageId::SdCard: - res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry( - title_id, type); - break; - default: - UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage)); - } - + const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type); if (res == nullptr) { // TODO(DarkLordZach): Find the right error code to use here return RESULT_UNKNOWN; } + const auto romfs = res->GetRomFS(); if (romfs == nullptr) { // TODO(DarkLordZach): Find the right error code to use here return RESULT_UNKNOWN; } + return MakeResult<VirtualFile>(romfs); } +std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage, + ContentRecordType type) const { + switch (storage) { + case StorageId::None: + return content_provider.GetEntry(title_id, type); + case StorageId::NandSystem: + return filesystem_controller.GetSystemNANDContents()->GetEntry(title_id, type); + case StorageId::NandUser: + return filesystem_controller.GetUserNANDContents()->GetEntry(title_id, type); + case StorageId::SdCard: + return filesystem_controller.GetSDMCContents()->GetEntry(title_id, type); + case StorageId::Host: + case StorageId::GameCard: + default: + UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage)); + return nullptr; + } +} + } // namespace FileSys diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index c5d40285c..ec704dfa8 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h @@ -13,8 +13,15 @@ namespace Loader { class AppLoader; } // namespace Loader +namespace Service::FileSystem { +class FileSystemController; +} + namespace FileSys { +class ContentProvider; +class NCA; + enum class ContentRecordType : u8; enum class StorageId : u8 { @@ -29,18 +36,26 @@ enum class StorageId : u8 { /// File system interface to the RomFS archive class RomFSFactory { public: - explicit RomFSFactory(Loader::AppLoader& app_loader); + explicit RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider, + Service::FileSystem::FileSystemController& controller); ~RomFSFactory(); void SetPackedUpdate(VirtualFile update_raw); - ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; - ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const; + [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; + [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, + ContentRecordType type) const; private: + [[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage, + ContentRecordType type) const; + VirtualFile file; VirtualFile update_raw; bool updatable; u64 ivfc_offset; + + ContentProvider& content_provider; + Service::FileSystem::FileSystemController& filesystem_controller; }; } // namespace FileSys diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp new file mode 100644 index 000000000..4505da758 --- /dev/null +++ b/src/core/frontend/applets/controller.cpp @@ -0,0 +1,81 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/controller.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/sm/sm.h" + +namespace Core::Frontend { + +ControllerApplet::~ControllerApplet() = default; + +DefaultControllerApplet::~DefaultControllerApplet() = default; + +void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, + ControllerParameters parameters) const { + LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); + + auto& npad = + Core::System::GetInstance() + .ServiceManager() + .GetService<Service::HID::Hid>("hid") + ->GetAppletResource() + ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); + + auto& players = Settings::values.players; + + const std::size_t min_supported_players = + parameters.enable_single_mode ? 1 : parameters.min_players; + + // Disconnect Handheld first. + npad.DisconnectNPadAtIndex(8); + + // Deduce the best configuration based on the input parameters. + for (std::size_t index = 0; index < players.size() - 2; ++index) { + // First, disconnect all controllers regardless of the value of keep_controllers_connected. + // This makes it easy to connect the desired controllers. + npad.DisconnectNPadAtIndex(index); + + // Only connect the minimum number of required players. + if (index >= min_supported_players) { + continue; + } + + // Connect controllers based on the following priority list from highest to lowest priority: + // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld + if (parameters.allow_pro_controller) { + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); + } else if (parameters.allow_dual_joycons) { + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); + } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { + // Assign left joycons to even player indices and right joycons to odd player indices. + // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and + // a right Joycon for Player 2 in 2 Player Assist mode. + if (index % 2 == 0) { + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); + } else { + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); + } + } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && + !Settings::values.use_docked_mode) { + // We should *never* reach here under any normal circumstances. + npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), + index); + } else { + UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); + } + } + + callback(); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h new file mode 100644 index 000000000..a227f15cd --- /dev/null +++ b/src/core/frontend/applets/controller.h @@ -0,0 +1,48 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> + +#include "common/common_types.h" + +namespace Core::Frontend { + +using BorderColor = std::array<u8, 4>; +using ExplainText = std::array<char, 0x81>; + +struct ControllerParameters { + s8 min_players{}; + s8 max_players{}; + bool keep_controllers_connected{}; + bool enable_single_mode{}; + bool enable_border_color{}; + std::vector<BorderColor> border_colors{}; + bool enable_explain_text{}; + std::vector<ExplainText> explain_text{}; + bool allow_pro_controller{}; + bool allow_handheld{}; + bool allow_dual_joycons{}; + bool allow_left_joycon{}; + bool allow_right_joycon{}; +}; + +class ControllerApplet { +public: + virtual ~ControllerApplet(); + + virtual void ReconfigureControllers(std::function<void()> callback, + ControllerParameters parameters) const = 0; +}; + +class DefaultControllerApplet final : public ControllerApplet { +public: + ~DefaultControllerApplet() override; + + void ReconfigureControllers(std::function<void()> callback, + ControllerParameters parameters) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 2b098b7c6..9da0d2829 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -119,11 +119,11 @@ using ButtonDevice = InputDevice<bool>; using AnalogDevice = InputDevice<std::tuple<float, float>>; /** - * A motion device is an input device that returns a tuple of accelerometer state vector and - * gyroscope state vector. + * A motion status is an object that returns a tuple of accelerometer state vector, + * gyroscope state vector, rotation state vector and orientation state matrix. * * For both vectors: - * x+ is the same direction as LEFT on D-pad. + * x+ is the same direction as RIGHT on D-pad. * y+ is normal to the touch screen, pointing outward. * z+ is the same direction as UP on D-pad. * @@ -133,8 +133,22 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>; * For gyroscope state vector: * Orientation is determined by right-hand rule. * Units: deg/sec + * + * For rotation state vector + * Units: rotations + * + * For orientation state matrix + * x vector + * y vector + * z vector + */ +using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>, + std::array<Common::Vec3f, 3>>; + +/** + * A motion device is an input device that returns a motion status object */ -using MotionDevice = InputDevice<std::tuple<Common::Vec3<float>, Common::Vec3<float>>>; +using MotionDevice = InputDevice<MotionStatus>; /** * A touch device is an input device that returns a tuple of two floats and a bool. The floats are diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 5ab204b9b..be9eba519 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -48,14 +48,15 @@ ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kern } ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, - Core::Memory::Memory& memory) { + Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { // Keep ServerSession alive until we're done working with it. if (!parent->Server()) { return ERR_SESSION_CLOSED_BY_REMOTE; } // Signal the server session that new data is available - return parent->Server()->HandleSyncRequest(std::move(thread), memory); + return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing); } } // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index c5f760d7d..e5e0690c2 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -16,6 +16,10 @@ namespace Core::Memory { class Memory; } +namespace Core::Timing { +class CoreTiming; +} + namespace Kernel { class KernelCore; @@ -42,7 +46,8 @@ public: return HANDLE_TYPE; } - ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); + ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); bool ShouldWait(const Thread* thread) const override; diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 36e3c26fb..b6f04dcea 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -188,7 +188,7 @@ private: /// Scheduler lock mechanisms. bool is_locked{}; - Common::SpinLock inner_lock{}; + std::mutex inner_lock; std::atomic<s64> scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 7e6391c6c..8c19f2534 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" @@ -185,10 +184,11 @@ ResultCode ServerSession::CompleteSyncRequest() { } ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, - Core::Memory::Memory& memory) { + Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { const ResultCode result = QueueSyncRequest(std::move(thread), memory); const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000}; - Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {}); + core_timing.ScheduleEvent(delay, request_event, {}); return result; } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 403aaf10b..d23e9ec68 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -18,8 +18,9 @@ class Memory; } namespace Core::Timing { +class CoreTiming; struct EventType; -} +} // namespace Core::Timing namespace Kernel { @@ -87,12 +88,14 @@ public: /** * Handle a sync request from the emulated application. * - * @param thread Thread that initiated the request. - * @param memory Memory context to handle the sync request under. + * @param thread Thread that initiated the request. + * @param memory Memory context to handle the sync request under. + * @param core_timing Core timing context to schedule the request event under. * * @returns ResultCode from the operation. */ - ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); + ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); bool ShouldWait(const Thread* thread) const override; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 01ae57053..bafd1ced7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -346,7 +346,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { SchedulerLock lock(system.Kernel()); thread->InvalidateHLECallback(); thread->SetStatus(ThreadStatus::WaitIPC); - session->SendSyncRequest(SharedFrom(thread), system.Memory()); + session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); } if (thread->HasHLECallback()) { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 7d92b25a3..d7a81f64a 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1192,7 +1192,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, - {123, nullptr, "GetPreviousProgramIndex"}, + {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, @@ -1554,6 +1554,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque rb.Push<u32>(0); } +void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<s32>(previous_program_index); +} + void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 6e69796ec..bcc06affe 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -288,11 +288,13 @@ private: void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); + void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); bool launch_popped_application_specific = false; bool launch_popped_account_preselect = false; + s32 previous_program_index{-1}; Kernel::EventPair gpu_error_detected_event; Kernel::EventPair friend_invitation_storage_channel_event; Core::System& system; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index c3261f3e6..4e0800f9a 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,6 +5,7 @@ #include <cstring> #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/profile_select.h" @@ -15,6 +16,7 @@ #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applets/controller.h" #include "core/hle/service/am/applets/error.h" #include "core/hle/service/am/applets/general_backend.h" #include "core/hle/service/am/applets/profile_select.h" @@ -140,14 +142,14 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, +AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, + ErrorApplet error, ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser, - ECommerceApplet e_commerce) - : parental_controls{std::move(parental_controls)}, error{std::move(error)}, - photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, - software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, - e_commerce{std::move(e_commerce)} {} + SoftwareKeyboard software_keyboard, WebBrowser web_browser) + : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)}, + parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)}, + profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)}, + web_browser{std::move(web_browser)} {} AppletFrontendSet::~AppletFrontendSet() = default; @@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { } void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { - if (set.parental_controls != nullptr) - frontend.parental_controls = std::move(set.parental_controls); - if (set.error != nullptr) + if (set.controller != nullptr) { + frontend.controller = std::move(set.controller); + } + + if (set.e_commerce != nullptr) { + frontend.e_commerce = std::move(set.e_commerce); + } + + if (set.error != nullptr) { frontend.error = std::move(set.error); - if (set.photo_viewer != nullptr) + } + + if (set.parental_controls != nullptr) { + frontend.parental_controls = std::move(set.parental_controls); + } + + if (set.photo_viewer != nullptr) { frontend.photo_viewer = std::move(set.photo_viewer); - if (set.profile_select != nullptr) + } + + if (set.profile_select != nullptr) { frontend.profile_select = std::move(set.profile_select); - if (set.software_keyboard != nullptr) + } + + if (set.software_keyboard != nullptr) { frontend.software_keyboard = std::move(set.software_keyboard); - if (set.web_browser != nullptr) + } + + if (set.web_browser != nullptr) { frontend.web_browser = std::move(set.web_browser); - if (set.e_commerce != nullptr) - frontend.e_commerce = std::move(set.e_commerce); + } } void AppletManager::SetDefaultAppletFrontendSet() { @@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() { } void AppletManager::SetDefaultAppletsIfMissing() { - if (frontend.parental_controls == nullptr) { - frontend.parental_controls = - std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + if (frontend.controller == nullptr) { + frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>(); + } + + if (frontend.e_commerce == nullptr) { + frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); } if (frontend.error == nullptr) { frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); } + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + } + if (frontend.photo_viewer == nullptr) { frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); } @@ -211,10 +238,6 @@ void AppletManager::SetDefaultAppletsIfMissing() { if (frontend.web_browser == nullptr) { frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); } - - if (frontend.e_commerce == nullptr) { - frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); - } } void AppletManager::ClearAll() { @@ -225,6 +248,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { switch (id) { case AppletId::Auth: return std::make_shared<Auth>(system, *frontend.parental_controls); + case AppletId::Controller: + return std::make_shared<Controller>(system, *frontend.controller); case AppletId::Error: return std::make_shared<Error>(system, *frontend.error); case AppletId::ProfileSelect: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index e75be86a2..a1f4cf897 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -17,6 +17,7 @@ class System; } namespace Core::Frontend { +class ControllerApplet; class ECommerceApplet; class ErrorApplet; class ParentalControlsApplet; @@ -155,19 +156,20 @@ protected: }; struct AppletFrontendSet { - using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; + using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; + using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>; using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; + using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; - using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>; AppletFrontendSet(); - AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, - PhotoViewer photo_viewer, ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser, - ECommerceApplet e_commerce); + AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error, + ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, + ProfileSelect profile_select, SoftwareKeyboard software_keyboard, + WebBrowser web_browser); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -176,13 +178,14 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; - ParentalControlsApplet parental_controls; + ControllerApplet controller; + ECommerceApplet e_commerce; ErrorApplet error; + ParentalControlsApplet parental_controls; PhotoViewer photo_viewer; ProfileSelect profile_select; SoftwareKeyboard software_keyboard; WebBrowser web_browser; - ECommerceApplet e_commerce; }; class AppletManager { diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp new file mode 100644 index 000000000..2151da783 --- /dev/null +++ b/src/core/hle/service/am/applets/controller.cpp @@ -0,0 +1,210 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/controller.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/controller.h" +#include "core/hle/service/hid/controllers/npad.h" + +namespace Service::AM::Applets { + +// This error code (0x183ACA) is thrown when the applet fails to initialize. +[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101}; +// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2. +[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102}; + +static Core::Frontend::ControllerParameters ConvertToFrontendParameters( + ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, + std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { + HID::Controller_NPad::NPadType npad_style_set; + npad_style_set.raw = private_arg.style_set; + + return { + .min_players = std::max(s8(1), header.player_count_min), + .max_players = header.player_count_max, + .keep_controllers_connected = header.enable_take_over_connection, + .enable_single_mode = header.enable_single_mode, + .enable_border_color = header.enable_identification_color, + .border_colors = identification_colors, + .enable_explain_text = enable_text, + .explain_text = text, + .allow_pro_controller = npad_style_set.pro_controller == 1, + .allow_handheld = npad_style_set.handheld == 1, + .allow_dual_joycons = npad_style_set.joycon_dual == 1, + .allow_left_joycon = npad_style_set.joycon_left == 1, + .allow_right_joycon = npad_style_set.joycon_right == 1, + }; +} + +Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_) {} + +Controller::~Controller() = default; + +void Controller::Initialize() { + Applet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Controller Applet."); + + LOG_DEBUG(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + library_applet_version = LibraryAppletVersion{common_args.library_version}; + + const auto private_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(private_arg_storage != nullptr); + + const auto& private_arg = private_arg_storage->GetData(); + ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); + + std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate)); + ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), + "Unknown ControllerSupportArgPrivate revision={} with size={}", + library_applet_version, controller_private_arg.arg_private_size); + + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: { + const auto user_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(user_arg_storage != nullptr); + + const auto& user_arg = user_arg_storage->GetData(); + switch (library_applet_version) { + case LibraryAppletVersion::Version3: + case LibraryAppletVersion::Version4: + case LibraryAppletVersion::Version5: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); + std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld)); + break; + case LibraryAppletVersion::Version7: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); + break; + default: + UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", + library_applet_version, controller_private_arg.arg_size); + ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); + break; + } + break; + } + case ControllerSupportMode::ShowControllerStrapGuide: + case ControllerSupportMode::ShowControllerFirmwareUpdate: + default: { + UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); + break; + } + } +} + +bool Controller::TransactionComplete() const { + return complete; +} + +ResultCode Controller::GetStatus() const { + return status; +} + +void Controller::ExecuteInteractive() { + UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); +} + +void Controller::Execute() { + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: { + const auto parameters = [this] { + switch (library_applet_version) { + case LibraryAppletVersion::Version3: + case LibraryAppletVersion::Version4: + case LibraryAppletVersion::Version5: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_old.header, + controller_user_arg_old.enable_explain_text, + std::vector<IdentificationColor>( + controller_user_arg_old.identification_colors.begin(), + controller_user_arg_old.identification_colors.end()), + std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(), + controller_user_arg_old.explain_text.end())); + case LibraryAppletVersion::Version7: + default: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_new.header, + controller_user_arg_new.enable_explain_text, + std::vector<IdentificationColor>( + controller_user_arg_new.identification_colors.begin(), + controller_user_arg_new.identification_colors.end()), + std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(), + controller_user_arg_new.explain_text.end())); + } + }(); + + is_single_mode = parameters.enable_single_mode; + + LOG_DEBUG(Service_HID, + "Controller Parameters: min_players={}, max_players={}, " + "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, " + "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, " + "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}", + parameters.min_players, parameters.max_players, + parameters.keep_controllers_connected, parameters.enable_single_mode, + parameters.enable_border_color, parameters.enable_explain_text, + parameters.allow_pro_controller, parameters.allow_handheld, + parameters.allow_dual_joycons, parameters.allow_left_joycon, + parameters.allow_right_joycon); + + frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters); + break; + } + case ControllerSupportMode::ShowControllerStrapGuide: + case ControllerSupportMode::ShowControllerFirmwareUpdate: + default: { + ConfigurationComplete(); + break; + } + } +} + +void Controller::ConfigurationComplete() { + ControllerSupportResultInfo result_info{}; + + const auto& players = Settings::values.players; + + // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. + // Otherwise, only count connected players from P1-P8. + result_info.player_count = + is_single_mode ? 1 + : static_cast<s8>(std::count_if( + players.begin(), players.end() - 2, + [](Settings::PlayerInput player) { return player.connected; })); + + result_info.selected_id = HID::Controller_NPad::IndexToNPad( + std::distance(players.begin(), + std::find_if(players.begin(), players.end(), + [](Settings::PlayerInput player) { return player.connected; }))); + + result_info.result = 0; + + LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", + result_info.player_count, result_info.selected_id, result_info.result); + + complete = true; + out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); + std::memcpy(out_data.data(), &result_info, out_data.size()); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data))); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h new file mode 100644 index 000000000..f7bb3fba9 --- /dev/null +++ b/src/core/hle/service/am/applets/controller.h @@ -0,0 +1,123 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <vector> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Core { +class System; +} + +namespace Service::AM::Applets { + +using IdentificationColor = std::array<u8, 4>; +using ExplainText = std::array<char, 0x81>; + +enum class LibraryAppletVersion : u32_le { + Version3 = 0x3, // 1.0.0 - 2.3.0 + Version4 = 0x4, // 3.0.0 - 5.1.0 + Version5 = 0x5, // 6.0.0 - 7.0.1 + Version7 = 0x7, // 8.0.0+ +}; + +enum class ControllerSupportMode : u8 { + ShowControllerSupport = 0, + ShowControllerStrapGuide = 1, + ShowControllerFirmwareUpdate = 2, +}; + +enum class ControllerSupportCaller : u8 { + Application = 0, + System = 1, +}; + +struct ControllerSupportArgPrivate { + u32 arg_private_size{}; + u32 arg_size{}; + bool flag_0{}; + bool flag_1{}; + ControllerSupportMode mode{}; + ControllerSupportCaller caller{}; + u32 style_set{}; + u32 joy_hold_type{}; +}; +static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, + "ControllerSupportArgPrivate has incorrect size."); + +struct ControllerSupportArgHeader { + s8 player_count_min{}; + s8 player_count_max{}; + bool enable_take_over_connection{}; + bool enable_left_justify{}; + bool enable_permit_joy_dual{}; + bool enable_single_mode{}; + bool enable_identification_color{}; +}; +static_assert(sizeof(ControllerSupportArgHeader) == 0x7, + "ControllerSupportArgHeader has incorrect size."); + +// LibraryAppletVersion 0x3, 0x4, 0x5 +struct ControllerSupportArgOld { + ControllerSupportArgHeader header{}; + std::array<IdentificationColor, 4> identification_colors{}; + bool enable_explain_text{}; + std::array<ExplainText, 4> explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgOld) == 0x21C, + "ControllerSupportArgOld has incorrect size."); + +// LibraryAppletVersion 0x7 +struct ControllerSupportArgNew { + ControllerSupportArgHeader header{}; + std::array<IdentificationColor, 8> identification_colors{}; + bool enable_explain_text{}; + std::array<ExplainText, 8> explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgNew) == 0x430, + "ControllerSupportArgNew has incorrect size."); + +struct ControllerSupportResultInfo { + s8 player_count{}; + INSERT_PADDING_BYTES(3); + u32 selected_id{}; + u32 result{}; +}; +static_assert(sizeof(ControllerSupportResultInfo) == 0xC, + "ControllerSupportResultInfo has incorrect size."); + +class Controller final : public Applet { +public: + explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_); + ~Controller() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void ConfigurationComplete(); + +private: + const Core::Frontend::ControllerApplet& frontend; + + LibraryAppletVersion library_applet_version; + ControllerSupportArgPrivate controller_private_arg; + ControllerSupportArgOld controller_user_arg_old; + ControllerSupportArgNew controller_user_arg_new; + bool complete{false}; + ResultCode status{RESULT_SUCCESS}; + bool is_single_mode{false}; + std::vector<u8> out_data; +}; + +} // 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 d8359abaa..a2d3ded7b 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -26,7 +26,7 @@ namespace Service::Audio { class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { public: - explicit IAudioRenderer(Core::System& system, AudioCore::AudioRendererParameter audren_params, + explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params, const std::size_t instance_number) : ServiceFramework("IAudioRenderer") { // clang-format off @@ -94,14 +94,15 @@ private: void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "(STUBBED) called"); - auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer()); + std::vector<u8> output_params(ctx.GetWriteBufferSize()); + auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer(), output_params); - if (result.Succeeded()) { - ctx.WriteBuffer(result.Unwrap()); + if (result.IsSuccess()) { + ctx.WriteBuffer(output_params); } IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result.Code()); + rb.Push(result); } void Start(Kernel::HLERequestContext& ctx) { @@ -346,7 +347,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { OpenAudioRendererImpl(ctx); } -static u64 CalculateNumPerformanceEntries(const AudioCore::AudioRendererParameter& params) { +static u64 CalculateNumPerformanceEntries(const AudioCommon::AudioRendererParameter& params) { // +1 represents the final mix. return u64{params.effect_count} + params.submix_count + params.sink_count + params.voice_count + 1; @@ -375,7 +376,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { constexpr u64 upsampler_manager_size = 0x48; // Calculates the part of the size that relates to mix buffers. - const auto calculate_mix_buffer_sizes = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_mix_buffer_sizes = [](const AudioCommon::AudioRendererParameter& params) { // As of 8.0.0 this is the maximum on voice channels. constexpr u64 max_voice_channels = 6; @@ -397,7 +398,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the portion of the size related to the mix data (and the sorting thereof). - const auto calculate_mix_info_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_mix_info_size = [](const AudioCommon::AudioRendererParameter& params) { // The size of the mixing info data structure. constexpr u64 mix_info_size = 0x940; @@ -447,7 +448,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size related to voice channel info. - const auto calculate_voice_info_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_voice_info_size = [](const AudioCommon::AudioRendererParameter& params) { constexpr u64 voice_info_size = 0x220; constexpr u64 voice_resource_size = 0xD0; @@ -461,7 +462,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size related to memory pools. - const auto calculate_memory_pools_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_memory_pools_size = [](const AudioCommon::AudioRendererParameter& params) { const u64 num_memory_pools = sizeof(s32) * (u64{params.effect_count} + params.voice_count); const u64 memory_pool_info_size = 0x20; return Common::AlignUp(num_memory_pools * memory_pool_info_size, info_field_alignment_size); @@ -469,7 +470,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { // Calculates the part of the size related to the splitter context. const auto calculate_splitter_context_size = - [](const AudioCore::AudioRendererParameter& params) -> u64 { + [](const AudioCommon::AudioRendererParameter& params) -> u64 { if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { return 0; } @@ -488,27 +489,29 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size related to the upsampler info. - const auto calculate_upsampler_info_size = [](const AudioCore::AudioRendererParameter& params) { - constexpr u64 upsampler_info_size = 0x280; - // Yes, using the buffer size over info alignment size is intentional here. - return Common::AlignUp(upsampler_info_size * (u64{params.submix_count} + params.sink_count), - buffer_alignment_size); - }; + const auto calculate_upsampler_info_size = + [](const AudioCommon::AudioRendererParameter& params) { + constexpr u64 upsampler_info_size = 0x280; + // Yes, using the buffer size over info alignment size is intentional here. + return Common::AlignUp(upsampler_info_size * + (u64{params.submix_count} + params.sink_count), + buffer_alignment_size); + }; // Calculates the part of the size related to effect info. - const auto calculate_effect_info_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_effect_info_size = [](const AudioCommon::AudioRendererParameter& params) { constexpr u64 effect_info_size = 0x2B0; return Common::AlignUp(effect_info_size * params.effect_count, info_field_alignment_size); }; // Calculates the part of the size related to audio sink info. - const auto calculate_sink_info_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_sink_info_size = [](const AudioCommon::AudioRendererParameter& params) { const u64 sink_info_size = 0x170; return Common::AlignUp(sink_info_size * params.sink_count, info_field_alignment_size); }; // Calculates the part of the size related to voice state info. - const auto calculate_voice_state_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_voice_state_size = [](const AudioCommon::AudioRendererParameter& params) { const u64 voice_state_size = 0x100; const u64 additional_size = buffer_alignment_size - 1; return Common::AlignUp(voice_state_size * params.voice_count + additional_size, @@ -516,7 +519,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size related to performance statistics. - const auto calculate_perf_size = [](const AudioCore::AudioRendererParameter& params) { + const auto calculate_perf_size = [](const AudioCommon::AudioRendererParameter& params) { // Extra size value appended to the end of the calculation. constexpr u64 appended = 128; @@ -543,79 +546,81 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size that relates to the audio command buffer. - const auto calculate_command_buffer_size = [](const AudioCore::AudioRendererParameter& params) { - constexpr u64 alignment = (buffer_alignment_size - 1) * 2; + const auto calculate_command_buffer_size = + [](const AudioCommon::AudioRendererParameter& params) { + constexpr u64 alignment = (buffer_alignment_size - 1) * 2; - if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { - constexpr u64 command_buffer_size = 0x18000; + if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { + constexpr u64 command_buffer_size = 0x18000; - return command_buffer_size + alignment; - } + return command_buffer_size + alignment; + } - // When the variadic command buffer is supported, this means - // the command generator for the audio renderer can issue commands - // that are (as one would expect), variable in size. So what we need to do - // is determine the maximum possible size for a few command data structures - // then multiply them by the amount of present commands indicated by the given - // respective audio parameters. + // When the variadic command buffer is supported, this means + // the command generator for the audio renderer can issue commands + // that are (as one would expect), variable in size. So what we need to do + // is determine the maximum possible size for a few command data structures + // then multiply them by the amount of present commands indicated by the given + // respective audio parameters. - constexpr u64 max_biquad_filters = 2; - constexpr u64 max_mix_buffers = 24; + constexpr u64 max_biquad_filters = 2; + constexpr u64 max_mix_buffers = 24; - constexpr u64 biquad_filter_command_size = 0x2C; + constexpr u64 biquad_filter_command_size = 0x2C; - constexpr u64 depop_mix_command_size = 0x24; - constexpr u64 depop_setup_command_size = 0x50; + constexpr u64 depop_mix_command_size = 0x24; + constexpr u64 depop_setup_command_size = 0x50; - constexpr u64 effect_command_max_size = 0x540; + constexpr u64 effect_command_max_size = 0x540; - constexpr u64 mix_command_size = 0x1C; - constexpr u64 mix_ramp_command_size = 0x24; - constexpr u64 mix_ramp_grouped_command_size = 0x13C; + constexpr u64 mix_command_size = 0x1C; + constexpr u64 mix_ramp_command_size = 0x24; + constexpr u64 mix_ramp_grouped_command_size = 0x13C; - constexpr u64 perf_command_size = 0x28; + constexpr u64 perf_command_size = 0x28; - constexpr u64 sink_command_size = 0x130; + constexpr u64 sink_command_size = 0x130; - constexpr u64 submix_command_max_size = - depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; + constexpr u64 submix_command_max_size = + depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; - constexpr u64 volume_command_size = 0x1C; - constexpr u64 volume_ramp_command_size = 0x20; + constexpr u64 volume_command_size = 0x1C; + constexpr u64 volume_ramp_command_size = 0x20; - constexpr u64 voice_biquad_filter_command_size = - biquad_filter_command_size * max_biquad_filters; - constexpr u64 voice_data_command_size = 0x9C; - const u64 voice_command_max_size = - (params.splitter_count * depop_setup_command_size) + - (voice_data_command_size + voice_biquad_filter_command_size + volume_ramp_command_size + - mix_ramp_grouped_command_size); + constexpr u64 voice_biquad_filter_command_size = + biquad_filter_command_size * max_biquad_filters; + constexpr u64 voice_data_command_size = 0x9C; + const u64 voice_command_max_size = + (params.splitter_count * depop_setup_command_size) + + (voice_data_command_size + voice_biquad_filter_command_size + + volume_ramp_command_size + mix_ramp_grouped_command_size); - // Now calculate the individual elements that comprise the size and add them together. - const u64 effect_commands_size = params.effect_count * effect_command_max_size; + // Now calculate the individual elements that comprise the size and add them together. + const u64 effect_commands_size = params.effect_count * effect_command_max_size; - const u64 final_mix_commands_size = - depop_mix_command_size + volume_command_size * max_mix_buffers; + const u64 final_mix_commands_size = + depop_mix_command_size + volume_command_size * max_mix_buffers; - const u64 perf_commands_size = - perf_command_size * (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); + const u64 perf_commands_size = + perf_command_size * + (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); - const u64 sink_commands_size = params.sink_count * sink_command_size; + const u64 sink_commands_size = params.sink_count * sink_command_size; - const u64 splitter_commands_size = - params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; + const u64 splitter_commands_size = + params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; - const u64 submix_commands_size = params.submix_count * submix_command_max_size; + const u64 submix_commands_size = params.submix_count * submix_command_max_size; - const u64 voice_commands_size = params.voice_count * voice_command_max_size; + const u64 voice_commands_size = params.voice_count * voice_command_max_size; - return effect_commands_size + final_mix_commands_size + perf_commands_size + - sink_commands_size + splitter_commands_size + submix_commands_size + - voice_commands_size + alignment; - }; + return effect_commands_size + final_mix_commands_size + perf_commands_size + + sink_commands_size + splitter_commands_size + submix_commands_size + + voice_commands_size + alignment; + }; IPC::RequestParser rp{ctx}; - const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); + const auto params = rp.PopRaw<AudioCommon::AudioRendererParameter>(); u64 size = 0; size += calculate_mix_buffer_sizes(params); @@ -681,7 +686,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); + const auto params = rp.PopRaw<AudioCommon::AudioRendererParameter>(); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 2cee1193c..54a5fb84b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -379,7 +379,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage( return FileSys::ERROR_ENTITY_NOT_FOUND; } - auto part = bis_factory->OpenPartitionStorage(id); + auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem()); if (part == nullptr) { return FileSys::ERROR_INVALID_ARGUMENT; } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e742497e1..b65d59373 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -193,7 +193,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { controller.battery_level[0] = BATTERY_FULL; controller.battery_level[1] = BATTERY_FULL; controller.battery_level[2] = BATTERY_FULL; - styleset_changed_events[controller_idx].writable->Signal(); + + SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); } void Controller_NPad::OnInit() { @@ -249,6 +250,9 @@ void Controller_NPad::OnLoadInputDevices() { std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); + std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, + players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, + motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); } } @@ -265,6 +269,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { auto& rstick_entry = npad_pad_states[controller_idx].r_stick; const auto& button_state = buttons[controller_idx]; const auto& analog_state = sticks[controller_idx]; + const auto& motion_state = motions[controller_idx]; const auto [stick_l_x_f, stick_l_y_f] = analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); const auto [stick_r_x_f, stick_r_y_f] = @@ -359,6 +364,45 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* continue; } const u32 npad_index = static_cast<u32>(i); + + const std::array<SixAxisGeneric*, 6> controller_sixaxes{ + &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, + &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, + }; + + for (auto* sixaxis_sensor : controller_sixaxes) { + sixaxis_sensor->common.entry_count = 16; + sixaxis_sensor->common.total_entry_count = 17; + + const auto& last_entry = + sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks(); + sixaxis_sensor->common.last_entry_index = + (sixaxis_sensor->common.last_entry_index + 1) % 17; + + auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + // Try to read sixaxis sensor states + std::array<MotionDevice, 2> motion_devices; + + if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { + sixaxis_at_rest = true; + for (std::size_t e = 0; e < motion_devices.size(); ++e) { + const auto& device = motions[i][e]; + if (device) { + std::tie(motion_devices[e].accel, motion_devices[e].gyro, + motion_devices[e].rotation, motion_devices[e].orientation) = + device->GetStatus(); + sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; + } + } + } + RequestPadStateUpdate(npad_index); auto& pad_state = npad_pad_states[npad_index]; @@ -376,6 +420,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_entry.connection_status.raw = 0; libnx_entry.connection_status.IsConnected.Assign(1); + auto& full_sixaxis_entry = + npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; + auto& handheld_sixaxis_entry = + npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; + auto& dual_left_sixaxis_entry = + npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; + auto& dual_right_sixaxis_entry = + npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; + auto& left_sixaxis_entry = + npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; + auto& right_sixaxis_entry = + npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; switch (controller_type) { case NPadControllerType::None: @@ -390,6 +446,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* main_controller.pad.r_stick = pad_state.r_stick; libnx_entry.connection_status.IsWired.Assign(1); + + if (sixaxis_sensors_enabled && motions[i][0]) { + full_sixaxis_entry.accel = motion_devices[0].accel; + full_sixaxis_entry.gyro = motion_devices[0].gyro; + full_sixaxis_entry.rotation = motion_devices[0].rotation; + full_sixaxis_entry.orientation = motion_devices[0].orientation; + } break; case NPadControllerType::Handheld: handheld_entry.connection_status.raw = 0; @@ -408,6 +471,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_entry.connection_status.IsRightJoyConnected.Assign(1); libnx_entry.connection_status.IsLeftJoyWired.Assign(1); libnx_entry.connection_status.IsRightJoyWired.Assign(1); + + if (sixaxis_sensors_enabled && motions[i][0]) { + handheld_sixaxis_entry.accel = motion_devices[0].accel; + handheld_sixaxis_entry.gyro = motion_devices[0].gyro; + handheld_sixaxis_entry.rotation = motion_devices[0].rotation; + handheld_sixaxis_entry.orientation = motion_devices[0].orientation; + } break; case NPadControllerType::JoyDual: dual_entry.connection_status.raw = 0; @@ -420,6 +490,21 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); libnx_entry.connection_status.IsRightJoyConnected.Assign(1); + + if (sixaxis_sensors_enabled && motions[i][0]) { + // Set motion for the left joycon + dual_left_sixaxis_entry.accel = motion_devices[0].accel; + dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; + dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; + dual_left_sixaxis_entry.orientation = motion_devices[0].orientation; + } + if (sixaxis_sensors_enabled && motions[i][1]) { + // Set motion for the right joycon + dual_right_sixaxis_entry.accel = motion_devices[1].accel; + dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; + dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; + dual_right_sixaxis_entry.orientation = motion_devices[1].orientation; + } break; case NPadControllerType::JoyLeft: left_entry.connection_status.raw = 0; @@ -430,6 +515,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* left_entry.pad.r_stick = pad_state.r_stick; libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); + + if (sixaxis_sensors_enabled && motions[i][0]) { + left_sixaxis_entry.accel = motion_devices[0].accel; + left_sixaxis_entry.gyro = motion_devices[0].gyro; + left_sixaxis_entry.rotation = motion_devices[0].rotation; + left_sixaxis_entry.orientation = motion_devices[0].orientation; + } break; case NPadControllerType::JoyRight: right_entry.connection_status.raw = 0; @@ -440,6 +532,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* right_entry.pad.r_stick = pad_state.r_stick; libnx_entry.connection_status.IsRightJoyConnected.Assign(1); + + if (sixaxis_sensors_enabled && motions[i][1]) { + right_sixaxis_entry.accel = motion_devices[1].accel; + right_sixaxis_entry.gyro = motion_devices[1].gyro; + right_sixaxis_entry.rotation = motion_devices[1].rotation; + right_sixaxis_entry.orientation = motion_devices[1].orientation; + } break; case NPadControllerType::Pokeball: pokeball_entry.connection_status.raw = 0; @@ -518,13 +617,17 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, last_processed_vibration = vibrations.back(); } +Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { + return last_processed_vibration; +} + std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; return styleset_event.readable; } -Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { - return last_processed_vibration; +void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { + styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal(); } void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { @@ -534,7 +637,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected) { if (!connected) { - DisconnectNPad(IndexToNPad(npad_index)); + DisconnectNPadAtIndex(npad_index); return; } @@ -554,16 +657,19 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz } void Controller_NPad::DisconnectNPad(u32 npad_id) { - const auto npad_index = NPadIdToIndex(npad_id); - connected_controllers[npad_index].is_connected = false; + DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); +} + +void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { Settings::values.players[npad_index].connected = false; + connected_controllers[npad_index].is_connected = false; auto& controller = shared_memory_entries[npad_index]; controller.joy_styles.raw = 0; // Zero out controller.device_type.raw = 0; controller.properties.raw = 0; - styleset_changed_events[npad_index].writable->Signal(); + SignalStyleSetChangedEvent(IndexToNPad(npad_index)); } void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { @@ -574,6 +680,14 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo return gyroscope_zero_drift_mode; } +bool Controller_NPad::IsSixAxisSensorAtRest() const { + return sixaxis_at_rest; +} + +void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { + sixaxis_sensors_enabled = six_axis_status; +} + void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { const auto npad_index_1 = NPadIdToIndex(npad_id_1); const auto npad_index_2 = NPadIdToIndex(npad_id_2); @@ -666,13 +780,13 @@ void Controller_NPad::ClearAllConnectedControllers() { } void Controller_NPad::DisconnectAllConnectedControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { controller.is_connected = false; } } void Controller_NPad::ConnectAllDisconnectedControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { if (controller.type != NPadControllerType::None && !controller.is_connected) { controller.is_connected = true; } @@ -680,7 +794,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() { } void Controller_NPad::ClearAllControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { controller.type = NPadControllerType::None; controller.is_connected = false; } @@ -728,92 +842,4 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const return false; } -Controller_NPad::NPadControllerType Controller_NPad::DecideBestController( - NPadControllerType priority) const { - if (IsControllerSupported(priority)) { - return priority; - } - const auto is_docked = Settings::values.use_docked_mode; - if (is_docked && priority == NPadControllerType::Handheld) { - priority = NPadControllerType::JoyDual; - if (IsControllerSupported(priority)) { - return priority; - } - } - std::vector<NPadControllerType> priority_list; - switch (priority) { - case NPadControllerType::ProController: - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::Handheld: - priority_list.push_back(NPadControllerType::JoyDual); - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyDual: - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyLeft: - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyRight: - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::Pokeball: - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - break; - default: - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - break; - } - - const auto iter = std::find_if(priority_list.begin(), priority_list.end(), - [this](auto type) { return IsControllerSupported(type); }); - if (iter == priority_list.end()) { - UNIMPLEMENTED_MSG("Could not find supported controller!"); - return priority; - } - - return *iter; -} - } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index ad25c6fbf..78e7c320b 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -115,17 +115,23 @@ public: void VibrateController(const std::vector<u32>& controller_ids, const std::vector<Vibration>& vibrations); - std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; Vibration GetLastVibration() const; + std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; + void SignalStyleSetChangedEvent(u32 npad_id) const; + // Adds a new controller at an index. void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); // Adds a new controller at an index with connection status. void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); void DisconnectNPad(u32 npad_id); + void DisconnectNPadAtIndex(std::size_t index); + void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; + bool IsSixAxisSensorAtRest() const; + void SetSixAxisEnabled(bool six_axis_status); LedPattern GetLedPattern(u32 npad_id); void SetVibrationEnabled(bool can_vibrate); bool IsVibrationEnabled() const; @@ -248,6 +254,24 @@ private: }; static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); + struct SixAxisStates { + s64_le timestamp{}; + INSERT_PADDING_WORDS(2); + s64_le timestamp2{}; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + Common::Vec3f rotation{}; + std::array<Common::Vec3f, 3> orientation{}; + s64_le always_one{1}; + }; + static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); + + struct SixAxisGeneric { + CommonHeader common{}; + std::array<SixAxisStates, 17> sixaxis{}; + }; + static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); + enum class ColorReadError : u32_le { ReadOk = 0, ColorDoesntExist = 1, @@ -277,6 +301,13 @@ private: }; }; + struct MotionDevice { + Common::Vec3f accel; + Common::Vec3f gyro; + Common::Vec3f rotation; + std::array<Common::Vec3f, 3> orientation; + }; + struct NPadEntry { NPadType joy_styles; NPadAssignments pad_assignment; @@ -296,9 +327,12 @@ private: NPadGeneric pokeball_states; NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be // relying on this for the time being - INSERT_PADDING_BYTES( - 0x708 * - 6); // TODO(ogniK): SixAxis states, require more information before implementation + SixAxisGeneric sixaxis_full; + SixAxisGeneric sixaxis_handheld; + SixAxisGeneric sixaxis_dual_left; + SixAxisGeneric sixaxis_dual_right; + SixAxisGeneric sixaxis_left; + SixAxisGeneric sixaxis_right; NPadDevice device_type; NPadProperties properties; INSERT_PADDING_WORDS(1); @@ -315,21 +349,24 @@ private: void InitNewlyAddedController(std::size_t controller_idx); bool IsControllerSupported(NPadControllerType controller) const; - NPadControllerType DecideBestController(NPadControllerType priority) const; void RequestPadStateUpdate(u32 npad_id); u32 press_state{}; NPadType style{}; std::array<NPadEntry, 10> shared_memory_entries{}; - std::array< + using ButtonArray = std::array< std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, - 10> - buttons; - std::array< + 10>; + using StickArray = std::array< std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, - 10> - sticks; + 10>; + using MotionArray = std::array< + std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, + 10>; + ButtonArray buttons; + StickArray sticks; + MotionArray motions; std::vector<u32> supported_npad_id_types{}; NpadHoldType hold_type{NpadHoldType::Vertical}; // Each controller should have their own styleset changed event @@ -338,6 +375,8 @@ private: std::array<ControllerHolder, 10> connected_controllers{}; GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; bool can_controllers_vibrate{true}; + bool sixaxis_sensors_enabled{true}; + bool sixaxis_at_rest{true}; std::array<ControllerPad, 10> npad_pad_states{}; bool is_in_lr_assignment_mode{false}; Core::System& system; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9453134bf..1d96f705f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -164,8 +164,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {56, nullptr, "ActivateJoyXpad"}, {58, nullptr, "GetJoyXpadLifoHandle"}, {59, nullptr, "GetJoyXpadIds"}, - {60, nullptr, "ActivateSixAxisSensor"}, - {61, nullptr, "DeactivateSixAxisSensor"}, + {60, &Hid::ActivateSixAxisSensor, "ActivateSixAxisSensor"}, + {61, &Hid::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"}, {62, nullptr, "GetSixAxisSensorLifoHandle"}, {63, nullptr, "ActivateJoySixAxisSensor"}, {64, nullptr, "DeactivateJoySixAxisSensor"}, @@ -329,6 +329,31 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { rb.Push(0); } +void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); + LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); + + LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; @@ -484,13 +509,13 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { const auto handle{rp.Pop<u32>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, - applet_resource_user_id); + LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. - rb.Push(true); + rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .IsSixAxisSensorAtRest()); } void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index efb07547f..e04aaf1e9 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -86,6 +86,8 @@ private: void CreateAppletResource(Kernel::HLERequestContext& ctx); void ActivateXpad(Kernel::HLERequestContext& ctx); void GetXpadIDs(Kernel::HLERequestContext& ctx); + void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx); + void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx); void ActivateDebugPad(Kernel::HLERequestContext& ctx); void ActivateTouchScreen(Kernel::HLERequestContext& ctx); void ActivateMouse(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 5e2d769a4..a0469ffbd 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> #include <atomic> #include "common/logging/log.h" @@ -72,10 +73,10 @@ private: std::array<u8, 10> uuid; u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it // mean something else - INSERT_PADDING_BYTES(0x15); + std::array<u8, 0x15> padding_1; u32_le protocol; u32_le tag_type; - INSERT_PADDING_BYTES(0x2c); + std::array<u8, 0x2c> padding_2; }; static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size"); @@ -213,13 +214,15 @@ private: LOG_DEBUG(Service_NFP, "called"); IPC::ResponseBuilder rb{ctx, 2}; - auto amiibo = nfp_interface.GetAmiiboBuffer(); - TagInfo tag_info{}; - 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 - tag_info.tag_type = 2; + const auto& amiibo = nfp_interface.GetAmiiboBuffer(); + const TagInfo tag_info{ + .uuid = amiibo.uuid, + .uuid_length = static_cast<u8>(tag_info.uuid.size()), + .padding_1 = {}, + .protocol = 1, // TODO(ogniK): Figure out actual values + .tag_type = 2, + .padding_2 = {}, + }; ctx.WriteBuffer(tag_info); rb.Push(RESULT_SUCCESS); } @@ -236,7 +239,7 @@ private: LOG_DEBUG(Service_NFP, "called"); IPC::ResponseBuilder rb{ctx, 2}; - auto amiibo = nfp_interface.GetAmiiboBuffer(); + const auto& amiibo = nfp_interface.GetAmiiboBuffer(); ctx.WriteBuffer(amiibo.model_info); rb.Push(RESULT_SUCCESS); } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 538f28495..76b3533ec 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -72,25 +72,6 @@ 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. - */ -[[maybe_unused]] static std::string MakeFunctionString(std::string_view name, - std::string_view 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); - - std::string function_string = fmt::format("function '{}': port={}", name, port_name); - for (int i = 1; i <= num_params; ++i) { - function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]); - } - return function_string; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker) : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} @@ -105,10 +86,9 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) port_installed = true; } -void ServiceFrameworkBase::InstallAsNamedPort() { +void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { ASSERT(!port_installed); - auto& kernel = Core::System::GetInstance().Kernel(); auto [server_port, client_port] = Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); server_port->SetHleHandler(shared_from_this()); @@ -116,10 +96,9 @@ void ServiceFrameworkBase::InstallAsNamedPort() { port_installed = true; } -std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { +std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) { ASSERT(!port_installed); - auto& kernel = Core::System::GetInstance().Kernel(); auto [server_port, client_port] = Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); auto port = MakeResult(std::move(server_port)).Unwrap(); @@ -191,9 +170,6 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co return RESULT_SUCCESS; } -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Module interface - /// Initialize ServiceManager void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 022d885b6..a01ef3353 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -63,9 +63,9 @@ public: /// Creates a port pair and registers this service with the given ServiceManager. void InstallAsService(SM::ServiceManager& service_manager); /// Creates a port pair and registers it on the kernel's global port registry. - void InstallAsNamedPort(); + void InstallAsNamedPort(Kernel::KernelCore& kernel); /// Creates and returns an unregistered port for the service. - std::shared_ptr<Kernel::ClientPort> CreatePort(); + std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel); void InvokeRequest(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index d872de16c..9c1da361b 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -19,7 +19,7 @@ constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); -ServiceManager::ServiceManager() = default; +ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} ServiceManager::~ServiceManager() = default; void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { @@ -27,11 +27,11 @@ void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { } static ResultCode ValidateServiceName(const std::string& name) { - if (name.size() <= 0 || name.size() > 8) { + if (name.empty() || name.size() > 8) { LOG_ERROR(Service_SM, "Invalid service name! service={}", name); return ERR_INVALID_NAME; } - if (name.find('\0') != std::string::npos) { + if (name.rfind('\0') != std::string::npos) { LOG_ERROR(Service_SM, "A non null terminated service was passed"); return ERR_INVALID_NAME; } @@ -43,13 +43,13 @@ void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, ASSERT(self->sm_interface.expired()); auto sm = std::make_shared<SM>(self, kernel); - sm->InstallAsNamedPort(); + sm->InstallAsNamedPort(kernel); self->sm_interface = sm; self->controller_interface = std::make_unique<Controller>(); } -ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService( - std::string name, unsigned int max_sessions) { +ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, + u32 max_sessions) { CASCADE_CODE(ValidateServiceName(name)); @@ -58,7 +58,6 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService( return ERR_ALREADY_REGISTERED; } - auto& kernel = Core::System::GetInstance().Kernel(); auto [server_port, client_port] = Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index aabf166b7..6790c86f0 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -48,11 +48,11 @@ class ServiceManager { public: static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel); - ServiceManager(); + explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, - unsigned int max_sessions); + u32 max_sessions); ResultCode UnregisterService(const std::string& name); ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); @@ -79,6 +79,9 @@ private: /// Map of registered services, retrieved using GetServicePort or ConnectToService. std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services; + + /// Kernel context + Kernel::KernelCore& kernel; }; } // namespace Service::SM diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h index 31ef6b821..2d53e52b6 100644 --- a/src/core/hle/service/sockets/blocking_worker.h +++ b/src/core/hle/service/sockets/blocking_worker.h @@ -29,7 +29,7 @@ namespace Service::Sockets { * Worker abstraction to execute blocking calls on host without blocking the guest thread * * @tparam Service Service where the work is executed - * @tparam ...Types Types of work to execute + * @tparam Types Types of work to execute */ template <class Service, class... Types> class BlockingWorker { @@ -109,9 +109,8 @@ private: while (keep_running) { work_event.Wait(); - const auto visit_fn = [service, &keep_running](auto&& w) { - using T = std::decay_t<decltype(w)>; - if constexpr (std::is_same_v<T, std::monostate>) { + const auto visit_fn = [service, &keep_running]<typename T>(T&& w) { + if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) { keep_running = false; } else { w.Execute(service); diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 803505452..7b9dd42d8 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -491,7 +491,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u for (PollFD& pollfd : fds) { ASSERT(pollfd.revents == 0); - if (pollfd.fd > MAX_FD || pollfd.fd < 0) { + if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) { LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd); pollfd.revents = 0; return {0, Errno::SUCCESS}; @@ -764,6 +764,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& SockAddrIn guest_addr_in; std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); addr_in = Translate(guest_addr_in); + p_addr_in = &addr_in; } return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in)); @@ -795,7 +796,7 @@ s32 BSD::FindFreeFileDescriptorHandle() noexcept { } bool BSD::IsFileDescriptorValid(s32 fd) const noexcept { - if (fd > MAX_FD || fd < 0) { + if (fd > static_cast<s32>(MAX_FD) || fd < 0) { LOG_ERROR(Service, "Invalid file descriptor handle={}", fd); return false; } @@ -809,7 +810,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept { bool BSD::IsBlockingSocket(s32 fd) const noexcept { // Inform invalid sockets as non-blocking // This way we avoid using a worker thread as it will fail without blocking host - if (fd > MAX_FD || fd < 0) { + if (fd > static_cast<s32>(MAX_FD) || fd < 0) { return false; } if (!file_descriptors[fd]) { diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index 2be8f642d..139743e1d 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp @@ -131,21 +131,21 @@ u16 TranslatePollEventsToGuest(u16 flags) { Network::SockAddrIn Translate(SockAddrIn value) { ASSERT(value.len == 0 || value.len == sizeof(value)); - Network::SockAddrIn result; - result.family = Translate(static_cast<Domain>(value.family)); - result.ip = value.ip; - result.portno = value.portno >> 8 | value.portno << 8; - return result; + return { + .family = Translate(static_cast<Domain>(value.family)), + .ip = value.ip, + .portno = static_cast<u16>(value.portno >> 8 | value.portno << 8), + }; } SockAddrIn Translate(Network::SockAddrIn value) { - SockAddrIn result; - result.len = sizeof(result); - result.family = static_cast<u8>(Translate(value.family)); - result.portno = value.portno >> 8 | value.portno << 8; - result.ip = value.ip; - result.zeroes = {}; - return result; + return { + .len = sizeof(SockAddrIn), + .family = static_cast<u8>(Translate(value.family)), + .portno = static_cast<u16>(value.portno >> 8 | value.portno << 8), + .ip = value.ip, + .zeroes = {}, + }; } Network::ShutdownHow Translate(ShutdownHow how) { diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 134e83412..394a1bf26 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -89,7 +89,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua } AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load( - Kernel::Process& process) { + Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -141,9 +141,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect continue; } - const bool should_pass_arguments{std::strcmp(module, "rtld") == 0}; - const auto tentative_next_load_addr{AppLoader_NSO::LoadModule( - process, *module_file, code_size, should_pass_arguments, false)}; + const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; + const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( + process, system, *module_file, code_size, should_pass_arguments, false); if (!tentative_next_load_addr) { return {ResultStatus::ErrorLoadingNSO, {}}; } @@ -168,9 +168,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect } const VAddr load_addr{next_load_addr}; - const bool should_pass_arguments{std::strcmp(module, "rtld") == 0}; - const auto tentative_next_load_addr{AppLoader_NSO::LoadModule( - process, *module_file, load_addr, should_pass_arguments, true, pm)}; + const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; + const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( + process, system, *module_file, load_addr, should_pass_arguments, true, pm); if (!tentative_next_load_addr) { return {ResultStatus::ErrorLoadingNSO, {}}; } @@ -192,8 +192,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect // Register the RomFS if a ".romfs" file was found if (romfs_iter != files.end() && *romfs_iter != nullptr) { romfs = *romfs_iter; - Core::System::GetInstance().GetFileSystemController().RegisterRomFS( - std::make_unique<FileSys::RomFSFactory>(*this)); + system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( + *this, system.GetContentProvider(), system.GetFileSystemController())); } is_loaded = true; diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 1c0a354a4..35d340317 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -9,6 +9,10 @@ #include "core/file_sys/program_metadata.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace Loader { /** @@ -37,7 +41,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadIcon(std::vector<u8>& buffer) override; diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 8f7615115..dca1fcb18 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -383,7 +383,8 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) { return FileType::Error; } -AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) { +AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process, + [[maybe_unused]] Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index 7ef7770a6..3527933ad 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h @@ -8,6 +8,10 @@ #include "common/common_types.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace Loader { /// Loads an ELF/AXF file @@ -26,7 +30,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; }; } // namespace Loader diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 40fa03ad1..5981bcd21 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -43,7 +43,8 @@ FileType AppLoader_KIP::GetFileType() const { : FileType::Error; } -AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) { +AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process, + [[maybe_unused]] Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h index 12ca40269..dee05a7b5 100644 --- a/src/core/loader/kip.h +++ b/src/core/loader/kip.h @@ -6,6 +6,10 @@ #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace FileSys { class KIP; } @@ -26,7 +30,7 @@ public: FileType GetFileType() const override; - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; private: std::unique_ptr<FileSys::KIP> kip; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 227ecc704..ac60b097a 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -15,6 +15,10 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/vfs.h" +namespace Core { +class System; +} + namespace FileSys { class NACP; } // namespace FileSys @@ -154,9 +158,10 @@ public: /** * Load the application and return the created Process instance * @param process The newly created process. + * @param system The system that this process is being loaded under. * @return The status result of the operation. */ - virtual LoadResult Load(Kernel::Process& process) = 0; + virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0; /** * Get the code (typically .code section) of the application diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index a152981a0..49028177b 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -41,7 +41,8 @@ FileType AppLoader_NAX::GetFileType() const { return IdentifyTypeImpl(*nax); } -AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) { +AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process, + [[maybe_unused]] Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -65,7 +66,7 @@ AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) { return {nca_status, {}}; } - const auto result = nca_loader->Load(process); + const auto result = nca_loader->Load(process, system); if (result.first != ResultStatus::Success) { return result; } diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index eaec9bf58..c2b7722b5 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -8,10 +8,12 @@ #include "common/common_types.h" #include "core/loader/loader.h" -namespace FileSys { +namespace Core { +class System; +} +namespace FileSys { class NAX; - } // namespace FileSys namespace Loader { @@ -33,7 +35,7 @@ public: FileType GetFileType() const override; - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 5a0469978..fa694de37 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -31,7 +31,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) { return FileType::Error; } -AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) { +AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -52,14 +52,14 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) { directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true); - const auto load_result = directory_loader->Load(process); + const auto load_result = directory_loader->Load(process, system); if (load_result.first != ResultStatus::Success) { return load_result; } if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) { - Core::System::GetInstance().GetFileSystemController().RegisterRomFS( - std::make_unique<FileSys::RomFSFactory>(*this)); + system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( + *this, system.GetContentProvider(), system.GetFileSystemController())); } is_loaded = true; diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index e47dc0e47..711070294 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -8,6 +8,10 @@ #include "core/file_sys/vfs.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace FileSys { class NCA; } @@ -33,7 +37,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 906544bc9..9fb5eddad 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -208,7 +208,7 @@ bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& fi return LoadNroImpl(process, file.ReadAllBytes(), file.GetName()); } -AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) { +AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -218,8 +218,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) { } if (romfs != nullptr) { - Core::System::GetInstance().GetFileSystemController().RegisterRomFS( - std::make_unique<FileSys::RomFSFactory>(*this)); + system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( + *this, system.GetContentProvider(), system.GetFileSystemController())); } is_loaded = true; diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 4593d48fb..a2aab2ecc 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -10,6 +10,10 @@ #include "common/common_types.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace FileSys { class NACP; } @@ -37,7 +41,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadProgramId(u64& out_program_id) override; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 575330a86..60373cc5f 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -71,7 +71,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) { return FileType::NSO; } -std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, +std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::System& system, const FileSys::VfsFile& file, VAddr load_base, bool should_pass_arguments, bool load_into_process, std::optional<FileSys::PatchManager> pm) { @@ -148,7 +148,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, // Apply cheats if they exist and the program has a valid title ID if (pm) { - auto& system = Core::System::GetInstance(); system.SetCurrentProcessBuildID(nso_header.build_id); const auto cheats = pm->CreateCheatList(system, nso_header.build_id); if (!cheats.empty()) { @@ -166,7 +165,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, return load_base + image_size; } -AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) { +AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -175,7 +174,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) { // Load module const VAddr base_address = process.PageTable().GetCodeRegionStart(); - if (!LoadModule(process, *file, base_address, true, true)) { + if (!LoadModule(process, system, *file, base_address, true, true)) { return {ResultStatus::ErrorLoadingNSO, {}}; } diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index b210830f0..4bd47787d 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -12,6 +12,10 @@ #include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace Kernel { class Process; } @@ -80,12 +84,12 @@ public: return IdentifyType(file); } - static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file, - VAddr load_base, bool should_pass_arguments, - bool load_into_process, + static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system, + const FileSys::VfsFile& file, VAddr load_base, + bool should_pass_arguments, bool load_into_process, std::optional<FileSys::PatchManager> pm = {}); - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadNSOModules(Modules& modules) override; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 13950fc08..15e528fa8 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -71,7 +71,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { return FileType::Error; } -AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) { +AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -99,15 +99,14 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) { return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; } - const auto result = secondary_loader->Load(process); + const auto result = secondary_loader->Load(process, system); if (result.first != ResultStatus::Success) { return result; } FileSys::VirtualFile update_raw; if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { - Core::System::GetInstance().GetFileSystemController().SetPackedUpdate( - std::move(update_raw)); + system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); } is_loaded = true; diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 868b028d3..b27deb686 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -9,6 +9,10 @@ #include "core/file_sys/vfs.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace FileSys { class NACP; class NSP; @@ -35,7 +39,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 7186ad1ff..25e83af0f 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -49,7 +49,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { return FileType::Error; } -AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) { +AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::System& system) { if (is_loaded) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } @@ -66,15 +66,14 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) { return {ResultStatus::ErrorMissingProductionKeyFile, {}}; } - const auto result = nca_loader->Load(process); + const auto result = nca_loader->Load(process, system); if (result.first != ResultStatus::Success) { return result; } FileSys::VirtualFile update_raw; if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { - Core::System::GetInstance().GetFileSystemController().SetPackedUpdate( - std::move(update_raw)); + system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); } is_loaded = true; diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 618ae2f47..04aea286f 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -9,6 +9,10 @@ #include "core/file_sys/vfs.h" #include "core/loader/loader.h" +namespace Core { +class System; +} + namespace FileSys { class NACP; class XCI; @@ -35,7 +39,7 @@ public: return IdentifyType(file); } - LoadResult Load(Kernel::Process& process) override; + LoadResult Load(Kernel::Process& process, Core::System& system) override; ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; u64 ReadRomFSIVFCOffset() const override; diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index e503118dd..29284a42d 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -19,10 +19,24 @@ #include "core/memory/cheat_engine.h" namespace Core::Memory { - +namespace { constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; +std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { + auto end_index = start_index; + while (data[end_index] != match) { + ++end_index; + if (end_index > data.size() || + (end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) { + return {}; + } + } + + return data.substr(start_index, end_index - start_index); +} +} // Anonymous namespace + StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) : metadata(metadata), system(system) {} @@ -82,26 +96,9 @@ CheatParser::~CheatParser() = default; TextCheatParser::~TextCheatParser() = default; -namespace { -template <char match> -std::string_view ExtractName(std::string_view data, std::size_t start_index) { - auto end_index = start_index; - while (data[end_index] != match) { - ++end_index; - if (end_index > data.size() || - (end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) { - return {}; - } - } - - return data.substr(start_index, end_index - start_index); -} -} // Anonymous namespace - -std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system, - std::string_view data) const { +std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const { std::vector<CheatEntry> out(1); - std::optional<u64> current_entry = std::nullopt; + std::optional<u64> current_entry; for (std::size_t i = 0; i < data.size(); ++i) { if (::isspace(data[i])) { @@ -115,7 +112,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system, return {}; } - const auto name = ExtractName<'}'>(data, i + 1); + const auto name = ExtractName(data, i + 1, '}'); if (name.empty()) { return {}; } @@ -132,7 +129,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system, current_entry = out.size(); out.emplace_back(); - const auto name = ExtractName<']'>(data, i + 1); + const auto name = ExtractName(data, i + 1, ']'); if (name.empty()) { return {}; } diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index fa039a831..a31002346 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -47,8 +47,7 @@ class CheatParser { public: virtual ~CheatParser(); - virtual std::vector<CheatEntry> Parse(const Core::System& system, - std::string_view data) const = 0; + [[nodiscard]] virtual std::vector<CheatEntry> Parse(std::string_view data) const = 0; }; // CheatParser implementation that parses text files @@ -56,7 +55,7 @@ class TextCheatParser final : public CheatParser { public: ~TextCheatParser() override; - std::vector<CheatEntry> Parse(const Core::System& system, std::string_view data) const override; + [[nodiscard]] std::vector<CheatEntry> Parse(std::string_view data) const override; }; // Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming diff --git a/src/core/settings.h b/src/core/settings.h index 80f0d95a7..9834f44bb 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -152,6 +152,7 @@ struct Values { bool vibration_enabled; + bool motion_enabled; std::string motion_device; std::string touch_device; TouchscreenInput touchscreen; |