diff options
Diffstat (limited to 'src/core')
115 files changed, 2152 insertions, 355 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a6b56c9c6..3416854db 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,3 +1,9 @@ +if (YUZU_ENABLE_BOXCAT) + set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h) +else() + set(BCAT_BOXCAT_ADDITIONAL_SOURCES) +endif() + add_library(core STATIC arm/arm_interface.h arm/arm_interface.cpp @@ -82,6 +88,8 @@ add_library(core STATIC file_sys/vfs_concat.h file_sys/vfs_layered.cpp file_sys/vfs_layered.h + file_sys/vfs_libzip.cpp + file_sys/vfs_libzip.h file_sys/vfs_offset.cpp file_sys/vfs_offset.h file_sys/vfs_real.cpp @@ -241,6 +249,9 @@ add_library(core STATIC hle/service/audio/errors.h hle/service/audio/hwopus.cpp hle/service/audio/hwopus.h + hle/service/bcat/backend/backend.cpp + hle/service/bcat/backend/backend.h + ${BCAT_BOXCAT_ADDITIONAL_SOURCES} hle/service/bcat/bcat.cpp hle/service/bcat/bcat.h hle/service/bcat/module.cpp @@ -499,6 +510,15 @@ create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) + +if (YUZU_ENABLE_BOXCAT) + get_directory_property(OPENSSL_LIBS + DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl + DEFINITION OPENSSL_LIBS) + target_compile_definitions(core PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT -DYUZU_ENABLE_BOXCAT) + target_link_libraries(core PRIVATE httplib json-headers ${OPENSSL_LIBS} zip) +endif() + if (ENABLE_WEB_SERVICE) target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) target_link_libraries(core PRIVATE web_service) diff --git a/src/core/core.cpp b/src/core/core.cpp index 76bb2bae9..75a7ffb97 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -163,6 +163,7 @@ struct System::Impl { gpu_core = VideoCore::CreateGPU(system); is_powered_on = true; + exit_lock = false; LOG_DEBUG(Core, "Initialized OK"); @@ -249,6 +250,7 @@ struct System::Impl { perf_stats->GetMeanFrametime()); is_powered_on = false; + exit_lock = false; // Shutdown emulation session renderer.reset(); @@ -333,9 +335,11 @@ struct System::Impl { std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; CpuCoreManager cpu_core_manager; bool is_powered_on = false; + bool exit_lock = false; std::unique_ptr<Memory::CheatEngine> cheat_engine; std::unique_ptr<Tools::Freezer> memory_freezer; + std::array<u8, 0x20> build_id{}; /// Frontend applets Service::AM::Applets::AppletManager applet_manager; @@ -629,6 +633,22 @@ const Service::APM::Controller& System::GetAPMController() const { return impl->apm_controller; } +void System::SetExitLock(bool locked) { + impl->exit_lock = locked; +} + +bool System::GetExitLock() const { + return impl->exit_lock; +} + +void System::SetCurrentProcessBuildID(std::array<u8, 32> id) { + impl->build_id = id; +} + +const std::array<u8, 32>& System::GetCurrentProcessBuildID() const { + return impl->build_id; +} + System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { return impl->Init(*this, emu_window); } diff --git a/src/core/core.h b/src/core/core.h index d2a3c82d8..f49b7fbf9 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -326,6 +326,14 @@ public: const Service::APM::Controller& GetAPMController() const; + void SetExitLock(bool locked); + + bool GetExitLock() const; + + void SetCurrentProcessBuildID(std::array<u8, 0x20> id); + + const std::array<u8, 0x20>& GetCurrentProcessBuildID() const; + private: System(); diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 46aceec3d..222fc95ba 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -423,7 +423,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, const RSAKeyPair<2048>& key) { const auto issuer = ticket.GetData().issuer; - if (issuer == std::array<u8, 0x40>{}) + if (IsAllZeroArray(issuer)) return {}; if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 8f758d6d9..0af44f340 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -136,4 +136,9 @@ u64 BISFactory::GetFullNANDTotalSpace() const { return static_cast<u64>(Settings::values.nand_total_size); } +VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { + return GetOrCreateDirectoryRelative(nand_root, + fmt::format("/system/save/bcat/{:016X}", title_id)); +} + } // namespace FileSys diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index bdfe728c9..8f0451c98 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h @@ -61,6 +61,8 @@ public: u64 GetUserNANDTotalSpace() const; u64 GetFullNANDTotalSpace() const; + VirtualDir GetBCATDirectory(u64 title_id) const; + private: VirtualDir nand_root; VirtualDir load_root; diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp new file mode 100644 index 000000000..8bdaa7e4a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.cpp @@ -0,0 +1,79 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <string> +#include <zip.h> +#include "common/logging/backend.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_libzip.h" +#include "core/file_sys/vfs_vector.h" + +namespace FileSys { + +VirtualDir ExtractZIP(VirtualFile file) { + zip_error_t error{}; + + const auto data = file->ReadAllBytes(); + std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{ + zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close}; + if (src == nullptr) + return nullptr; + + std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error), + zip_close}; + if (zip == nullptr) + return nullptr; + + std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>(); + + const auto num_entries = zip_get_num_entries(zip.get(), 0); + + zip_stat_t stat{}; + zip_stat_init(&stat); + + for (std::size_t i = 0; i < num_entries; ++i) { + const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat); + if (stat_res == -1) + return nullptr; + + const std::string name(stat.name); + if (name.empty()) + continue; + + if (name.back() != '/') { + std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file{ + zip_fopen_index(zip.get(), i, 0), zip_fclose}; + + std::vector<u8> buf(stat.size); + if (zip_fread(file.get(), buf.data(), buf.size()) != buf.size()) + return nullptr; + + const auto parts = FileUtil::SplitPathComponents(stat.name); + const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back()); + + std::shared_ptr<VectorVfsDirectory> dtrv = out; + for (std::size_t j = 0; j < parts.size() - 1; ++j) { + if (dtrv == nullptr) + return nullptr; + const auto subdir = dtrv->GetSubdirectory(parts[j]); + if (subdir == nullptr) { + const auto temp = std::make_shared<VectorVfsDirectory>( + std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]); + dtrv->AddDirectory(temp); + dtrv = temp; + } else { + dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir); + } + } + + if (dtrv == nullptr) + return nullptr; + dtrv->AddFile(new_file); + } + } + + return out; +} + +} // namespace FileSys diff --git a/src/core/file_sys/vfs_libzip.h b/src/core/file_sys/vfs_libzip.h new file mode 100644 index 000000000..f68af576a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.h @@ -0,0 +1,13 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs_types.h" + +namespace FileSys { + +VirtualDir ExtractZIP(VirtualFile zip); + +} // namespace FileSys diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index a7c55e116..0c0f7ed6e 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -70,7 +70,7 @@ public: protected: void Get(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); ProfileBase profile_base{}; ProfileData data{}; if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { @@ -89,7 +89,7 @@ protected: } void GetBase(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); ProfileBase profile_base{}; if (profile_manager.GetProfileBase(user_id, profile_base)) { IPC::ResponseBuilder rb{ctx, 16}; @@ -263,7 +263,7 @@ private: }; void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called"); + LOG_DEBUG(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount())); @@ -272,7 +272,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -280,21 +280,21 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { } void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called"); + LOG_DEBUG(Service_ACC, "called"); ctx.WriteBuffer(profile_manager->GetAllUsers()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called"); + LOG_DEBUG(Service_ACC, "called"); ctx.WriteBuffer(profile_manager->GetOpenUsers()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_ACC, "called"); + LOG_DEBUG(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser()); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 6c594dcaf..34409e0c3 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -31,6 +31,7 @@ #include "core/hle/service/am/tcap.h" #include "core/hle/service/apm/controller.h" #include "core/hle/service/apm/interface.h" +#include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -46,15 +47,20 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; -constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; +enum class LaunchParameterKind : u32 { + ApplicationSpecific = 1, + AccountPreselectedUser = 2, +}; + +constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; -struct LaunchParameters { +struct LaunchParameterAccountPreselectedUser { u32_le magic; u32_le is_account_selected; u128 current_user; INSERT_PADDING_BYTES(0x70); }; -static_assert(sizeof(LaunchParameters) == 0x88); +static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); IWindowController::IWindowController(Core::System& system_) : ServiceFramework("IWindowController"), system{system_} { @@ -232,12 +238,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { IDebugFunctions::~IDebugFunctions() = default; -ISelfController::ISelfController(Core::System& system_, - std::shared_ptr<NVFlinger::NVFlinger> nvflinger_) - : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) { +ISelfController::ISelfController(Core::System& system, + std::shared_ptr<NVFlinger::NVFlinger> nvflinger) + : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Exit"}, + {0, &ISelfController::Exit, "Exit"}, {1, &ISelfController::LockExit, "LockExit"}, {2, &ISelfController::UnlockExit, "UnlockExit"}, {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, @@ -282,7 +288,7 @@ ISelfController::ISelfController(Core::System& system_, RegisterHandlers(functions); - auto& kernel = system_.Kernel(); + auto& kernel = system.Kernel(); launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "ISelfController:LaunchableEvent"); @@ -298,15 +304,28 @@ ISelfController::ISelfController(Core::System& system_, ISelfController::~ISelfController() = default; +void ISelfController::Exit(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.Shutdown(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLock(true); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLock(false); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -550,6 +569,10 @@ void AppletMessageQueue::OperationModeChanged() { on_operation_mode_changed.writable->Signal(); } +void AppletMessageQueue::RequestExit() { + PushMessage(AppletMessage::ExitRequested); +} + ICommonStateGetter::ICommonStateGetter(Core::System& system, std::shared_ptr<AppletMessageQueue> msg_queue) : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { @@ -1066,7 +1089,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); } @@ -1111,26 +1134,55 @@ void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx } void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + IPC::RequestParser rp{ctx}; + const auto kind = rp.PopEnum<LaunchParameterKind>(); - LaunchParameters params{}; + LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); - params.magic = POP_LAUNCH_PARAMETER_MAGIC; - params.is_account_selected = 1; + if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { + const auto backend = BCAT::CreateBackendFromSettings( + [this](u64 tid) { return system.GetFileSystemController().GetBCATDirectory(tid); }); + const auto build_id_full = Core::System::GetInstance().GetCurrentProcessBuildID(); + u64 build_id{}; + std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); - Account::ProfileManager profile_manager{}; - const auto uuid = profile_manager.GetUser(Settings::values.current_user); - ASSERT(uuid); - params.current_user = uuid->uuid; + const auto data = + backend->GetLaunchParameter({Core::CurrentProcess()->GetTitleID(), build_id}); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + if (data.has_value()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<AM::IStorage>(*data); + launch_popped_application_specific = true; + return; + } + } else if (kind == LaunchParameterKind::AccountPreselectedUser && + !launch_popped_account_preselect) { + LaunchParameterAccountPreselectedUser params{}; - rb.Push(RESULT_SUCCESS); + params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; + params.is_account_selected = 1; + + Account::ProfileManager profile_manager{}; + const auto uuid = profile_manager.GetUser(Settings::values.current_user); + ASSERT(uuid); + params.current_user = uuid->uuid; - std::vector<u8> buffer(sizeof(LaunchParameters)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + + std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), ¶ms, buffer.size()); - rb.PushIpcInterface<AM::IStorage>(buffer); + rb.PushIpcInterface<AM::IStorage>(buffer); + launch_popped_account_preselect = true; + return; + } + + LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERR_NO_DATA_IN_CHANNEL); } void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 28f870302..9169eb2bd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -45,6 +45,7 @@ class AppletMessageQueue { public: enum class AppletMessage : u32 { NoMessage = 0, + ExitRequested = 4, FocusStateChanged = 15, OperationModeChanged = 30, PerformanceModeChanged = 31, @@ -59,6 +60,7 @@ public: AppletMessage PopMessage(); std::size_t GetMessageCount() const; void OperationModeChanged(); + void RequestExit(); private: std::queue<AppletMessage> messages; @@ -123,6 +125,7 @@ public: ~ISelfController() override; private: + void Exit(Kernel::HLERequestContext& ctx); void LockExit(Kernel::HLERequestContext& ctx); void UnlockExit(Kernel::HLERequestContext& ctx); void EnterFatalSection(Kernel::HLERequestContext& ctx); @@ -151,6 +154,8 @@ private: u32 idle_time_detection_extension = 0; u64 num_fatal_sections_entered = 0; bool is_auto_sleep_disabled = false; + + Core::System& system; }; class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { @@ -250,6 +255,8 @@ private: void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); + bool launch_popped_application_specific = false; + bool launch_popped_account_preselect = false; Kernel::EventPair gpu_error_detected_event; Core::System& system; }; diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 0e0d10858..2e3e45915 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -19,6 +19,8 @@ class NVFlinger; namespace AM { +class AppletMessageQueue; + class AppletAE final : public ServiceFramework<AppletAE> { public: explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 99a65e7b5..758da792d 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -19,6 +19,8 @@ class NVFlinger; namespace AM { +class AppletMessageQueue; + class AppletOE final : public ServiceFramework<AppletOE> { public: explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index d2e35362f..720fe766f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -157,6 +157,10 @@ AppletManager::AppletManager(Core::System& system_) : system{system_} {} AppletManager::~AppletManager() = default; +const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { + return frontend; +} + void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { if (set.parental_controls != nullptr) frontend.parental_controls = std::move(set.parental_controls); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 764c3418c..226be88b1 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -190,6 +190,8 @@ public: explicit AppletManager(Core::System& system_); ~AppletManager(); + const AppletFrontendSet& GetAppletFrontendSet() const; + void SetAppletFrontendSet(AppletFrontendSet set); void SetDefaultAppletFrontendSet(); void SetDefaultAppletsIfMissing(); diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index d3e97776b..e9cf1e840 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -29,9 +29,9 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { return (title_id & DLC_BASE_TITLE_ID_MASK) == base; } -static std::vector<u64> AccumulateAOCTitleIDs() { +static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { std::vector<u64> add_on_content; - const auto& rcu = Core::System::GetInstance().GetContentProvider(); + const auto& rcu = system.GetContentProvider(); const auto list = rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), @@ -47,7 +47,8 @@ static std::vector<u64> AccumulateAOCTitleIDs() { return add_on_content; } -AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { +AOC_U::AOC_U(Core::System& system) + : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "CountAddOnContentByApplicationId"}, @@ -65,7 +66,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "GetAddOnContentListChanged:Event"); } @@ -86,7 +87,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + const auto current = system.CurrentProcess()->GetTitleID(); const auto& disabled = Settings::values.disabled_addons[current]; if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { @@ -113,7 +114,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, process_id); - const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + const auto current = system.CurrentProcess()->GetTitleID(); std::vector<u32> out; const auto& disabled = Settings::values.disabled_addons[current]; @@ -159,7 +160,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + const auto title_id = system.CurrentProcess()->GetTitleID(); FileSys::PatchManager pm{title_id}; const auto res = pm.GetControlMetadata(); @@ -196,8 +197,8 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { rb.PushCopyObjects(aoc_change_event.readable); } -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<AOC_U>()->InstallAsService(service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<AOC_U>(system)->InstallAsService(service_manager); } } // namespace Service::AOC diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 5effea730..848b2f416 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -14,7 +14,7 @@ namespace Service::AOC { class AOC_U final : public ServiceFramework<AOC_U> { public: - AOC_U(); + explicit AOC_U(Core::System& system); ~AOC_U() override; private: @@ -26,9 +26,10 @@ private: std::vector<u64> add_on_content; Kernel::EventPair aoc_change_event; + Core::System& system; }; /// Registers all AOC services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::AOC diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp new file mode 100644 index 000000000..9b677debe --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.cpp @@ -0,0 +1,136 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/lock.h" +#include "core/hle/service/bcat/backend/backend.h" + +namespace Service::BCAT { + +ProgressServiceBackend::ProgressServiceBackend(std::string event_name) : impl{} { + auto& kernel{Core::System::GetInstance().Kernel()}; + event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Automatic, "ProgressServiceBackend:UpdateEvent:" + event_name); +} + +Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() { + return event.readable; +} + +DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { + return impl; +} + +void ProgressServiceBackend::SetNeedHLELock(bool need) { + need_hle_lock = need; +} + +void ProgressServiceBackend::SetTotalSize(u64 size) { + impl.total_bytes = size; + SignalUpdate(); +} + +void ProgressServiceBackend::StartConnecting() { + impl.status = DeliveryCacheProgressImpl::Status::Connecting; + SignalUpdate(); +} + +void ProgressServiceBackend::StartProcessingDataList() { + impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList; + SignalUpdate(); +} + +void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name, + std::string_view file_name, u64 file_size) { + impl.status = DeliveryCacheProgressImpl::Status::Downloading; + impl.current_downloaded_bytes = 0; + impl.current_total_bytes = file_size; + std::memcpy(impl.current_directory.data(), dir_name.data(), + std::min<u64>(dir_name.size(), 0x31ull)); + std::memcpy(impl.current_file.data(), file_name.data(), + std::min<u64>(file_name.size(), 0x31ull)); + SignalUpdate(); +} + +void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) { + impl.current_downloaded_bytes = downloaded; + SignalUpdate(); +} + +void ProgressServiceBackend::FinishDownloadingFile() { + impl.total_downloaded_bytes += impl.current_total_bytes; + SignalUpdate(); +} + +void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) { + impl.status = DeliveryCacheProgressImpl::Status::Committing; + impl.current_file.fill(0); + impl.current_downloaded_bytes = 0; + impl.current_total_bytes = 0; + std::memcpy(impl.current_directory.data(), dir_name.data(), + std::min<u64>(dir_name.size(), 0x31ull)); + SignalUpdate(); +} + +void ProgressServiceBackend::FinishDownload(ResultCode result) { + impl.total_downloaded_bytes = impl.total_bytes; + impl.status = DeliveryCacheProgressImpl::Status::Done; + impl.result = result; + SignalUpdate(); +} + +void ProgressServiceBackend::SignalUpdate() const { + if (need_hle_lock) { + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + event.writable->Signal(); + } else { + event.writable->Signal(); + } +} + +Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} + +Backend::~Backend() = default; + +NullBackend::NullBackend(const DirectoryGetter& getter) : Backend(std::move(getter)) {} + +NullBackend::~NullBackend() = default; + +bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, + title.build_id); + + progress.FinishDownload(RESULT_SUCCESS); + return true; +} + +bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name, + ProgressServiceBackend& progress) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id, + title.build_id, name); + + progress.FinishDownload(RESULT_SUCCESS); + return true; +} + +bool NullBackend::Clear(u64 title_id) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}"); + + return true; +} + +void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id, + Common::HexToString(passphrase)); +} + +std::optional<std::vector<u8>> NullBackend::GetLaunchParameter(TitleIDVersion title) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, + title.build_id); + return std::nullopt; +} + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h new file mode 100644 index 000000000..3f5d8b5dd --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.h @@ -0,0 +1,147 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <optional> +#include "common/common_types.h" +#include "core/file_sys/vfs_types.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" +#include "core/hle/result.h" + +namespace Service::BCAT { + +struct DeliveryCacheProgressImpl; + +using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>; +using Passphrase = std::array<u8, 0x20>; + +struct TitleIDVersion { + u64 title_id; + u64 build_id; +}; + +using DirectoryName = std::array<char, 0x20>; +using FileName = std::array<char, 0x20>; + +struct DeliveryCacheProgressImpl { + enum class Status : s32 { + None = 0x0, + Queued = 0x1, + Connecting = 0x2, + ProcessingDataList = 0x3, + Downloading = 0x4, + Committing = 0x5, + Done = 0x9, + }; + + Status status; + ResultCode result = RESULT_SUCCESS; + DirectoryName current_directory; + FileName current_file; + s64 current_downloaded_bytes; ///< Bytes downloaded on current file. + s64 current_total_bytes; ///< Bytes total on current file. + s64 total_downloaded_bytes; ///< Bytes downloaded on overall download. + s64 total_bytes; ///< Bytes total on overall download. + INSERT_PADDING_BYTES( + 0x198); ///< Appears to be unused in official code, possibly reserved for future use. +}; +static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200, + "DeliveryCacheProgressImpl has incorrect size."); + +// A class to manage the signalling to the game about BCAT download progress. +// Some of this class is implemented in module.cpp to avoid exposing the implementation structure. +class ProgressServiceBackend { + friend class IBcatService; + +public: + // Clients should call this with true if any of the functions are going to be called from a + // non-HLE thread and this class need to lock the hle mutex. (default is false) + void SetNeedHLELock(bool need); + + // Sets the number of bytes total in the entire download. + void SetTotalSize(u64 size); + + // Notifies the application that the backend has started connecting to the server. + void StartConnecting(); + // Notifies the application that the backend has begun accumulating and processing metadata. + void StartProcessingDataList(); + + // Notifies the application that a file is starting to be downloaded. + void StartDownloadingFile(std::string_view dir_name, std::string_view file_name, u64 file_size); + // Updates the progress of the current file to the size passed. + void UpdateFileProgress(u64 downloaded); + // Notifies the application that the current file has completed download. + void FinishDownloadingFile(); + + // Notifies the application that all files in this directory have completed and are being + // finalized. + void CommitDirectory(std::string_view dir_name); + + // Notifies the application that the operation completed with result code result. + void FinishDownload(ResultCode result); + +private: + explicit ProgressServiceBackend(std::string event_name); + + Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(); + DeliveryCacheProgressImpl& GetImpl(); + + void SignalUpdate() const; + + DeliveryCacheProgressImpl impl; + Kernel::EventPair event; + bool need_hle_lock = false; +}; + +// A class representing an abstract backend for BCAT functionality. +class Backend { +public: + explicit Backend(DirectoryGetter getter); + virtual ~Backend(); + + // Called when the backend is needed to synchronize the data for the game with title ID and + // version in title. A ProgressServiceBackend object is provided to alert the application of + // status. + virtual bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) = 0; + // Very similar to Synchronize, but only for the directory provided. Backends should not alter + // the data for any other directories. + virtual bool SynchronizeDirectory(TitleIDVersion title, std::string name, + ProgressServiceBackend& progress) = 0; + + // Removes all cached data associated with title id provided. + virtual bool Clear(u64 title_id) = 0; + + // Sets the BCAT Passphrase to be used with the associated title ID. + virtual void SetPassphrase(u64 title_id, const Passphrase& passphrase) = 0; + + // Gets the launch parameter used by AM associated with the title ID and version provided. + virtual std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) = 0; + +protected: + DirectoryGetter dir_getter; +}; + +// A backend of BCAT that provides no operation. +class NullBackend : public Backend { +public: + explicit NullBackend(const DirectoryGetter& getter); + ~NullBackend() override; + + bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; + bool SynchronizeDirectory(TitleIDVersion title, std::string name, + ProgressServiceBackend& progress) override; + + bool Clear(u64 title_id) override; + + void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; + + std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; +}; + +std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter); + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp new file mode 100644 index 000000000..e6ee0810b --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -0,0 +1,503 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <fmt/ostream.h> +#include <httplib.h> +#include <json.hpp> +#include <mbedtls/sha256.h> +#include "common/hex_util.h" +#include "common/logging/backend.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_libzip.h" +#include "core/file_sys/vfs_vector.h" +#include "core/frontend/applets/error.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/bcat/backend/boxcat.h" +#include "core/settings.h" + +namespace { + +// Prevents conflicts with windows macro called CreateFile +FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) { + return dir->CreateFile(name); +} + +// Prevents conflicts with windows macro called DeleteFile +bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) { + return dir->DeleteFile(name); +} + +} // Anonymous namespace + +namespace Service::BCAT { + +constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1}; + +constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org"; + +// Formatted using fmt with arg[0] = hex title id +constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat"; +constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam"; + +constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events"; + +constexpr char BOXCAT_API_VERSION[] = "1"; +constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu"; + +// HTTP status codes for Boxcat +enum class ResponseStatus { + Ok = 200, ///< Operation completed successfully. + BadClientVersion = 301, ///< The Boxcat-Client-Version doesn't match the server. + NoUpdate = 304, ///< The digest provided would match the new data, no need to update. + NoMatchTitleId = 404, ///< The title ID provided doesn't have a boxcat implementation. + NoMatchBuildId = 406, ///< The build ID provided is blacklisted (potentially because of format + ///< issues or whatnot) and has no data. +}; + +enum class DownloadResult { + Success = 0, + NoResponse, + GeneralWebError, + NoMatchTitleId, + NoMatchBuildId, + InvalidContentType, + GeneralFSError, + BadClientVersion, +}; + +constexpr std::array<const char*, 8> DOWNLOAD_RESULT_LOG_MESSAGES{ + "Success", + "There was no response from the server.", + "There was a general web error code returned from the server.", + "The title ID of the current game doesn't have a boxcat implementation. If you believe an " + "implementation should be added, contact yuzu support.", + "The build ID of the current version of the game is marked as incompatible with the current " + "BCAT distribution. Try upgrading or downgrading your game version or contacting yuzu support.", + "The content type of the web response was invalid.", + "There was a general filesystem error while saving the zip file.", + "The server is either too new or too old to serve the request. Try using the latest version of " + "an official release of yuzu.", +}; + +std::ostream& operator<<(std::ostream& os, DownloadResult result) { + return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result)); +} + +constexpr u32 PORT = 443; +constexpr u32 TIMEOUT_SECONDS = 30; +constexpr u64 VFS_COPY_BLOCK_SIZE = 1ull << 24; // 4MB + +namespace { + +std::string GetBINFilePath(u64 title_id) { + return fmt::format("{}bcat/{:016X}/launchparam.bin", + FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); +} + +std::string GetZIPFilePath(u64 title_id) { + return fmt::format("{}bcat/{:016X}/data.zip", + FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); +} + +// If the error is something the user should know about (build ID mismatch, bad client version), +// display an error. +void HandleDownloadDisplayResult(DownloadResult res) { + if (res == DownloadResult::Success || res == DownloadResult::NoResponse || + res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError || + res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) { + return; + } + + const auto& frontend{Core::System::GetInstance().GetAppletManager().GetAppletFrontendSet()}; + frontend.error->ShowCustomErrorText( + ResultCode(-1), "There was an error while attempting to use Boxcat.", + DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {}); +} + +bool VfsRawCopyProgress(FileSys::VirtualFile src, FileSys::VirtualFile dest, + std::string_view dir_name, ProgressServiceBackend& progress, + std::size_t block_size = 0x1000) { + if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + return false; + if (!dest->Resize(src->GetSize())) + return false; + + progress.StartDownloadingFile(dir_name, src->GetName(), src->GetSize()); + + std::vector<u8> temp(std::min(block_size, src->GetSize())); + for (std::size_t i = 0; i < src->GetSize(); i += block_size) { + const auto read = std::min(block_size, src->GetSize() - i); + + if (src->Read(temp.data(), read, i) != read) { + return false; + } + + if (dest->Write(temp.data(), read, i) != read) { + return false; + } + + progress.UpdateFileProgress(i); + } + + progress.FinishDownloadingFile(); + + return true; +} + +bool VfsRawCopyDProgressSingle(FileSys::VirtualDir src, FileSys::VirtualDir dest, + ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { + if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + return false; + + for (const auto& file : src->GetFiles()) { + const auto out_file = VfsCreateFileWrap(dest, file->GetName()); + if (!VfsRawCopyProgress(file, out_file, src->GetName(), progress, block_size)) { + return false; + } + } + progress.CommitDirectory(src->GetName()); + + return true; +} + +bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest, + ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { + if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + return false; + + for (const auto& dir : src->GetSubdirectories()) { + const auto out = dest->CreateSubdirectory(dir->GetName()); + if (!VfsRawCopyDProgressSingle(dir, out, progress, block_size)) { + return false; + } + } + + return true; +} + +} // Anonymous namespace + +class Boxcat::Client { +public: + Client(std::string path, u64 title_id, u64 build_id) + : path(std::move(path)), title_id(title_id), build_id(build_id) {} + + DownloadResult DownloadDataZip() { + return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS, + "application/zip"); + } + + DownloadResult DownloadLaunchParam() { + return DownloadInternal(fmt::format(BOXCAT_PATHNAME_LAUNCHPARAM, title_id), + TIMEOUT_SECONDS / 3, "application/octet-stream"); + } + +private: + DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds, + const std::string& content_type_name) { + if (client == nullptr) { + client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT, timeout_seconds); + } + + httplib::Headers headers{ + {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, + {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, + {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)}, + }; + + if (FileUtil::Exists(path)) { + FileUtil::IOFile file{path, "rb"}; + if (file.IsOpen()) { + std::vector<u8> bytes(file.GetSize()); + file.ReadBytes(bytes.data(), bytes.size()); + const auto digest = DigestFile(bytes); + headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)}); + } + } + + const auto response = client->Get(resolved_path.c_str(), headers); + if (response == nullptr) + return DownloadResult::NoResponse; + + if (response->status == static_cast<int>(ResponseStatus::NoUpdate)) + return DownloadResult::Success; + if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) + return DownloadResult::BadClientVersion; + if (response->status == static_cast<int>(ResponseStatus::NoMatchTitleId)) + return DownloadResult::NoMatchTitleId; + if (response->status == static_cast<int>(ResponseStatus::NoMatchBuildId)) + return DownloadResult::NoMatchBuildId; + if (response->status != static_cast<int>(ResponseStatus::Ok)) + return DownloadResult::GeneralWebError; + + const auto content_type = response->headers.find("content-type"); + if (content_type == response->headers.end() || + content_type->second.find(content_type_name) == std::string::npos) { + return DownloadResult::InvalidContentType; + } + + FileUtil::CreateFullPath(path); + FileUtil::IOFile file{path, "wb"}; + if (!file.IsOpen()) + return DownloadResult::GeneralFSError; + if (!file.Resize(response->body.size())) + return DownloadResult::GeneralFSError; + if (file.WriteBytes(response->body.data(), response->body.size()) != response->body.size()) + return DownloadResult::GeneralFSError; + + return DownloadResult::Success; + } + + using Digest = std::array<u8, 0x20>; + static Digest DigestFile(std::vector<u8> bytes) { + Digest out{}; + mbedtls_sha256(bytes.data(), bytes.size(), out.data(), 0); + return out; + } + + std::unique_ptr<httplib::Client> client; + std::string path; + u64 title_id; + u64 build_id; +}; + +Boxcat::Boxcat(DirectoryGetter getter) : Backend(std::move(getter)) {} + +Boxcat::~Boxcat() = default; + +void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, + ProgressServiceBackend& progress, + std::optional<std::string> dir_name = {}) { + progress.SetNeedHLELock(true); + + if (Settings::values.bcat_boxcat_local) { + LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); + const auto dir = dir_getter(title.title_id); + if (dir) + progress.SetTotalSize(dir->GetSize()); + progress.FinishDownload(RESULT_SUCCESS); + return; + } + + const auto zip_path{GetZIPFilePath(title.title_id)}; + Boxcat::Client client{zip_path, title.title_id, title.build_id}; + + progress.StartConnecting(); + + const auto res = client.DownloadDataZip(); + if (res != DownloadResult::Success) { + LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); + + if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { + FileUtil::Delete(zip_path); + } + + HandleDownloadDisplayResult(res); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + + progress.StartProcessingDataList(); + + FileUtil::IOFile zip{zip_path, "rb"}; + const auto size = zip.GetSize(); + std::vector<u8> bytes(size); + if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { + LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", zip_path); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + + const auto extracted = FileSys::ExtractZIP(std::make_shared<FileSys::VectorVfsFile>(bytes)); + if (extracted == nullptr) { + LOG_ERROR(Service_BCAT, "Boxcat failed to extract ZIP file!"); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + + if (dir_name == std::nullopt) { + progress.SetTotalSize(extracted->GetSize()); + + const auto target_dir = dir_getter(title.title_id); + if (target_dir == nullptr || !VfsRawCopyDProgress(extracted, target_dir, progress)) { + LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + } else { + const auto target_dir = dir_getter(title.title_id); + if (target_dir == nullptr) { + LOG_ERROR(Service_BCAT, "Boxcat failed to get directory for title ID!"); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + + const auto target_sub = target_dir->GetSubdirectory(*dir_name); + const auto source_sub = extracted->GetSubdirectory(*dir_name); + + progress.SetTotalSize(source_sub->GetSize()); + + std::vector<std::string> filenames; + { + const auto files = target_sub->GetFiles(); + std::transform(files.begin(), files.end(), std::back_inserter(filenames), + [](const auto& vfile) { return vfile->GetName(); }); + } + + for (const auto& filename : filenames) { + VfsDeleteFileWrap(target_sub, filename); + } + + if (target_sub == nullptr || source_sub == nullptr || + !VfsRawCopyDProgressSingle(source_sub, target_sub, progress)) { + LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); + progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); + return; + } + } + + progress.FinishDownload(RESULT_SUCCESS); +} + +bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { + is_syncing.exchange(true); + std::thread([this, title, &progress] { SynchronizeInternal(dir_getter, title, progress); }) + .detach(); + return true; +} + +bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name, + ProgressServiceBackend& progress) { + is_syncing.exchange(true); + std::thread( + [this, title, name, &progress] { SynchronizeInternal(dir_getter, title, progress, name); }) + .detach(); + return true; +} + +bool Boxcat::Clear(u64 title_id) { + if (Settings::values.bcat_boxcat_local) { + LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping clear."); + return true; + } + + const auto dir = dir_getter(title_id); + + std::vector<std::string> dirnames; + + for (const auto& subdir : dir->GetSubdirectories()) + dirnames.push_back(subdir->GetName()); + + for (const auto& subdir : dirnames) { + if (!dir->DeleteSubdirectoryRecursive(subdir)) + return false; + } + + return true; +} + +void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) { + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, + Common::HexToString(passphrase)); +} + +std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) { + const auto path{GetBINFilePath(title.title_id)}; + + if (Settings::values.bcat_boxcat_local) { + LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); + } else { + Boxcat::Client client{path, title.title_id, title.build_id}; + + const auto res = client.DownloadLaunchParam(); + if (res != DownloadResult::Success) { + LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); + + if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { + FileUtil::Delete(path); + } + + HandleDownloadDisplayResult(res); + return std::nullopt; + } + } + + FileUtil::IOFile bin{path, "rb"}; + const auto size = bin.GetSize(); + std::vector<u8> bytes(size); + if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { + LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!", + path); + return std::nullopt; + } + + return bytes; +} + +Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, + std::map<std::string, EventStatus>& games) { + httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT), + static_cast<int>(TIMEOUT_SECONDS)}; + + httplib::Headers headers{ + {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, + {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, + }; + + const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); + if (response == nullptr) + return StatusResult::Offline; + + if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) + return StatusResult::BadClientVersion; + + try { + nlohmann::json json = nlohmann::json::parse(response->body); + + if (!json["online"].get<bool>()) + return StatusResult::Offline; + + if (json["global"].is_null()) + global = std::nullopt; + else + global = json["global"].get<std::string>(); + + if (json["games"].is_array()) { + for (const auto object : json["games"]) { + if (object.is_object() && object.find("name") != object.end()) { + EventStatus detail{}; + if (object["header"].is_string()) { + detail.header = object["header"].get<std::string>(); + } else { + detail.header = std::nullopt; + } + + if (object["footer"].is_string()) { + detail.footer = object["footer"].get<std::string>(); + } else { + detail.footer = std::nullopt; + } + + if (object["events"].is_array()) { + for (const auto& event : object["events"]) { + if (!event.is_string()) + continue; + detail.events.push_back(event.get<std::string>()); + } + } + + games.insert_or_assign(object["name"], std::move(detail)); + } + } + } + + return StatusResult::Success; + } catch (const nlohmann::json::parse_error& e) { + return StatusResult::ParseError; + } +} + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h new file mode 100644 index 000000000..601151189 --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.h @@ -0,0 +1,58 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <map> +#include <optional> +#include "core/hle/service/bcat/backend/backend.h" + +namespace Service::BCAT { + +struct EventStatus { + std::optional<std::string> header; + std::optional<std::string> footer; + std::vector<std::string> events; +}; + +/// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and +/// doesn't require a switch or nintendo account. The content is controlled by the yuzu team. +class Boxcat final : public Backend { + friend void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, + ProgressServiceBackend& progress, + std::optional<std::string> dir_name); + +public: + explicit Boxcat(DirectoryGetter getter); + ~Boxcat() override; + + bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; + bool SynchronizeDirectory(TitleIDVersion title, std::string name, + ProgressServiceBackend& progress) override; + + bool Clear(u64 title_id) override; + + void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; + + std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; + + enum class StatusResult { + Success, + Offline, + ParseError, + BadClientVersion, + }; + + static StatusResult GetStatus(std::optional<std::string>& global, + std::map<std::string, EventStatus>& games); + +private: + std::atomic_bool is_syncing{false}; + + class Client; + std::unique_ptr<Client> client; +}; + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 179aa4949..c2f946424 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp @@ -6,11 +6,15 @@ namespace Service::BCAT { -BCAT::BCAT(std::shared_ptr<Module> module, const char* name) - : Module::Interface(std::move(module), name) { +BCAT::BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, const char* name) + : Module::Interface(std::move(module), fsc, name) { + // clang-format off static const FunctionInfo functions[] = { {0, &BCAT::CreateBcatService, "CreateBcatService"}, + {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"}, + {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"}, }; + // clang-format on RegisterHandlers(functions); } diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index 802bd689a..813073658 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h @@ -10,7 +10,8 @@ namespace Service::BCAT { class BCAT final : public Module::Interface { public: - explicit BCAT(std::shared_ptr<Module> module, const char* name); + explicit BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, + const char* name); ~BCAT() override; }; diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index b7bd738fc..b3fed56c7 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -2,34 +2,254 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cctype> +#include <mbedtls/md5.h> +#include "backend/boxcat.h" +#include "common/hex_util.h" #include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" +#include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/bcat/bcat.h" #include "core/hle/service/bcat/module.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/settings.h" namespace Service::BCAT { +constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; +constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; +constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; +constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; + +// The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files +// and if any of them have a non-zero result it just forwards that result. This is the FS error code +// for permission denied, which is the closest approximation of this scenario. +constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; + +using BCATDigest = std::array<u8, 0x10>; + +namespace { + +u64 GetCurrentBuildID() { + const auto& id = Core::System::GetInstance().GetCurrentProcessBuildID(); + u64 out{}; + std::memcpy(&out, id.data(), sizeof(u64)); + return out; +} + +// The digest is only used to determine if a file is unique compared to others of the same name. +// Since the algorithm isn't ever checked in game, MD5 is safe. +BCATDigest DigestFile(const FileSys::VirtualFile& file) { + BCATDigest out{}; + const auto bytes = file->ReadAllBytes(); + mbedtls_md5(bytes.data(), bytes.size(), out.data()); + return out; +} + +// For a name to be valid it must be non-empty, must have a null terminating character as the final +// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if +// file. +bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x20> name, + char match_char) { + const auto null_chars = std::count(name.begin(), name.end(), 0); + const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { + return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0'; + }); + if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { + LOG_ERROR(Service_BCAT, "Name passed was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return false; + } + + return true; +} + +bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { + return VerifyNameValidInternal(ctx, name, '-'); +} + +bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { + return VerifyNameValidInternal(ctx, name, '.'); +} + +} // Anonymous namespace + +struct DeliveryCacheDirectoryEntry { + FileName name; + u64 size; + BCATDigest digest; +}; + +class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { +public: + IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event, + const DeliveryCacheProgressImpl& impl) + : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, + {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(event); + } + + void GetImpl(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl)); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + Kernel::SharedPtr<Kernel::ReadableEvent> event; + const DeliveryCacheProgressImpl& impl; +}; + class IBcatService final : public ServiceFramework<IBcatService> { public: - IBcatService() : ServiceFramework("IBcatService") { + IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) { + // clang-format off static const FunctionInfo functions[] = { - {10100, nullptr, "RequestSyncDeliveryCache"}, - {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, + {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, + {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, - {30100, nullptr, "SetPassphrase"}, + {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, {30200, nullptr, "RegisterBackgroundDeliveryTask"}, {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, {30202, nullptr, "BlockDeliveryTask"}, {30203, nullptr, "UnblockDeliveryTask"}, {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, {90200, nullptr, "GetDeliveryList"}, - {90201, nullptr, "ClearDeliveryCacheStorage"}, + {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, {90300, nullptr, "GetPushNotificationLog"}, }; + // clang-format on RegisterHandlers(functions); } + +private: + enum class SyncType { + Normal, + Directory, + Count, + }; + + std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { + auto& backend{progress.at(static_cast<std::size_t>(type))}; + return std::make_shared<IDeliveryCacheProgressService>(backend.GetEvent(), + backend.GetImpl()); + } + + void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + backend.Synchronize({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, + progress.at(static_cast<std::size_t>(SyncType::Normal))); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); + } + + void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw<DirectoryName>(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, + name, + progress.at(static_cast<std::size_t>(SyncType::Directory))); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); + } + + void SetPassphrase(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw<u64>(); + + const auto passphrase_raw = ctx.ReadBuffer(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, + Common::HexToString(passphrase_raw)); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + } + + if (passphrase_raw.size() > 0x40) { + LOG_ERROR(Service_BCAT, "Passphrase too large!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + Passphrase passphrase{}; + std::memcpy(passphrase.data(), passphrase_raw.data(), + std::min(passphrase.size(), passphrase_raw.size())); + + backend.SetPassphrase(title_id, passphrase); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw<u64>(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + if (!backend.Clear(title_id)) { + LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_CLEAR_CACHE); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + Backend& backend; + + std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress{ + ProgressServiceBackend{"Normal"}, + ProgressServiceBackend{"Directory"}, + }; }; void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { @@ -37,20 +257,331 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IBcatService>(); + rb.PushIpcInterface<IBcatService>(*backend); +} + +class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { +public: + IDeliveryCacheFileService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheFileService::Open, "Open"}, + {1, &IDeliveryCacheFileService::Read, "Read"}, + {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, + {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto dir_name_raw = rp.PopRaw<DirectoryName>(); + const auto file_name_raw = rp.PopRaw<FileName>(); + + const auto dir_name = + Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); + const auto file_name = + Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); + + if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) + return; + + if (current_file != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + const auto dir = root->GetSubdirectory(dir_name); + + if (dir == nullptr) { + LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + current_file = dir->GetFile(file_name); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto offset{rp.PopRaw<u64>()}; + + auto size = ctx.GetWriteBufferSize(); + + LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + size = std::min<u64>(current_file->GetSize() - offset, size); + const auto buffer = current_file->ReadBytes(size, offset); + ctx.WriteBuffer(buffer); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(buffer.size()); + } + + void GetSize(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(current_file->GetSize()); + } + + void GetDigest(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(DigestFile(current_file)); + } + + FileSys::VirtualDir root; + FileSys::VirtualFile current_file; +}; + +class IDeliveryCacheDirectoryService final + : public ServiceFramework<IDeliveryCacheDirectoryService> { +public: + IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheDirectoryService::Open, "Open"}, + {1, &IDeliveryCacheDirectoryService::Read, "Read"}, + {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw<DirectoryName>(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + if (!VerifyNameValidDir(ctx, name_raw)) + return; + + if (current_dir != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + current_dir = root->GetSubdirectory(name); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Read(Kernel::HLERequestContext& ctx) { + auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); + + LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + write_size = std::min<u64>(write_size, files.size()); + std::vector<DeliveryCacheDirectoryEntry> entries(write_size); + std::transform( + files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { + FileName name{}; + std::memcpy(name.data(), file->GetName().data(), + std::min(file->GetName().size(), name.size())); + return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; + }); + + ctx.WriteBuffer(entries); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry)); + } + + void GetCount(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(files.size()); + } + + FileSys::VirtualDir root; + FileSys::VirtualDir current_dir; +}; + +class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { +public: + IDeliveryCacheStorageService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, + {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, + {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, + }; + // clang-format on + + RegisterHandlers(functions); + + for (const auto& subdir : root->GetSubdirectories()) { + DirectoryName name{}; + std::memcpy(name.data(), subdir->GetName().data(), + std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); + entries.push_back(name); + } + } + +private: + void CreateFileService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDeliveryCacheFileService>(root); + } + + void CreateDirectoryService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root); + } + + void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { + auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); + + LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); + + size = std::min<u64>(size, entries.size() - next_read_index); + ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); + next_read_index += size; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(size); + } + + FileSys::VirtualDir root; + std::vector<DirectoryName> entries; + u64 next_read_index = 0; +}; + +void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDeliveryCacheStorageService>( + fsc.GetBCATDirectory(Core::CurrentProcess()->GetTitleID())); +} + +void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( + Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw<u64>(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); +} + +std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) { + const auto backend = Settings::values.bcat_backend; + +#ifdef YUZU_ENABLE_BOXCAT + if (backend == "boxcat") + return std::make_unique<Boxcat>(std::move(getter)); +#endif + + return std::make_unique<NullBackend>(std::move(getter)); } -Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) - : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, + const char* name) + : ServiceFramework(name), module(std::move(module)), fsc(fsc), + backend(CreateBackendFromSettings([&fsc](u64 tid) { return fsc.GetBCATDirectory(tid); })) {} Module::Interface::~Interface() = default; -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(Core::System& system) { auto module = std::make_shared<Module>(); - std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); - std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager); - std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager); - std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager); + std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:a") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:m") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:u") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:s") + ->InstallAsService(system.ServiceManager()); } } // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index f0d63cab0..27469926a 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h @@ -6,23 +6,39 @@ #include "core/hle/service/service.h" -namespace Service::BCAT { +namespace Service { + +namespace FileSystem { +class FileSystemController; +} // namespace FileSystem + +namespace BCAT { + +class Backend; class Module final { public: class Interface : public ServiceFramework<Interface> { public: - explicit Interface(std::shared_ptr<Module> module, const char* name); + explicit Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, + const char* name); ~Interface() override; void CreateBcatService(Kernel::HLERequestContext& ctx); + void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx); + void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx); protected: + FileSystem::FileSystemController& fsc; + std::shared_ptr<Module> module; + std::unique_ptr<Backend> backend; }; }; /// Registers all BCAT services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(Core::System& system); + +} // namespace BCAT -} // namespace Service::BCAT +} // namespace Service diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 3c7ca2c44..afce581e5 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -16,7 +16,7 @@ namespace Service::BtDrv { class Bt final : public ServiceFramework<Bt> { public: - explicit Bt() : ServiceFramework{"bt"} { + explicit Bt(Core::System& system) : ServiceFramework{"bt"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "LeClientReadCharacteristic"}, @@ -33,7 +33,7 @@ public: // clang-format on RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); register_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); } @@ -163,9 +163,9 @@ public: } }; -void InstallInterfaces(SM::ServiceManager& sm) { +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<BtDrv>()->InstallAsService(sm); - std::make_shared<Bt>()->InstallAsService(sm); + std::make_shared<Bt>(system)->InstallAsService(sm); } } // namespace Service::BtDrv diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h index 164e56f43..191410dbc 100644 --- a/src/core/hle/service/btdrv/btdrv.h +++ b/src/core/hle/service/btdrv/btdrv.h @@ -8,9 +8,13 @@ namespace Service::SM { class ServiceManager; } +namespace Core { +class System; +} + namespace Service::BtDrv { /// Registers all BtDrv services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& sm); +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); } // namespace Service::BtDrv diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index b439ee7ec..920fc6ff7 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -17,7 +17,7 @@ namespace Service::BTM { class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { public: - explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} { + explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} { // clang-format off static const FunctionInfo functions[] = { {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, @@ -56,7 +56,7 @@ public: // clang-format on RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ScanEvent"); connection_event = Kernel::WritableEvent::CreateEventPair( @@ -108,7 +108,7 @@ private: class BTM_USR final : public ServiceFramework<BTM_USR> { public: - explicit BTM_USR() : ServiceFramework{"btm:u"} { + explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &BTM_USR::GetCore, "GetCore"}, @@ -123,8 +123,10 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IBtmUserCore>(); + rb.PushIpcInterface<IBtmUserCore>(system); } + + Core::System& system; }; class BTM final : public ServiceFramework<BTM> { @@ -268,11 +270,11 @@ private: } }; -void InstallInterfaces(SM::ServiceManager& sm) { +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<BTM>()->InstallAsService(sm); std::make_shared<BTM_DBG>()->InstallAsService(sm); std::make_shared<BTM_SYS>()->InstallAsService(sm); - std::make_shared<BTM_USR>()->InstallAsService(sm); + std::make_shared<BTM_USR>(system)->InstallAsService(sm); } } // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h index e6425a7e3..c6b878043 100644 --- a/src/core/hle/service/btm/btm.h +++ b/src/core/hle/service/btm/btm.h @@ -8,8 +8,12 @@ namespace Service::SM { class ServiceManager; } +namespace Core { +class System; +}; + namespace Service::BTM { -void InstallInterfaces(SM::ServiceManager& sm); +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); } // namespace Service::BTM diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 01fa06ad3..b2ebf6240 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -20,8 +20,8 @@ namespace Service::Fatal { -Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) - : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) + : ServiceFramework(name), module(std::move(module)), system(system) {} Module::Interface::~Interface() = default; @@ -64,7 +64,8 @@ enum class FatalType : u32 { ErrorScreen = 2, }; -static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { +static void GenerateErrorReport(Core::System& system, ResultCode error_code, + const FatalInfo& info) { const auto title_id = Core::CurrentProcess()->GetTitleID(); std::string crash_report = fmt::format( "Yuzu {}-{} crash report\n" @@ -101,18 +102,19 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { LOG_ERROR(Service_Fatal, "{}", crash_report); - Core::System::GetInstance().GetReporter().SaveCrashReport( + system.GetReporter().SaveCrashReport( title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc, info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace, info.backtrace_size, info.ArchAsString(), info.unk10); } -static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) { +static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type, + const FatalInfo& info) { LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", static_cast<u32>(fatal_type), error_code.raw); switch (fatal_type) { case FatalType::ErrorReportAndScreen: - GenerateErrorReport(error_code, info); + GenerateErrorReport(system, error_code, info); [[fallthrough]]; case FatalType::ErrorScreen: // Since we have no fatal:u error screen. We should just kill execution instead @@ -120,7 +122,7 @@ static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const F break; // Should not throw a fatal screen but should generate an error report case FatalType::ErrorReport: - GenerateErrorReport(error_code, info); + GenerateErrorReport(system, error_code, info); break; } } @@ -130,7 +132,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto error_code = rp.Pop<ResultCode>(); - ThrowFatalError(error_code, FatalType::ErrorScreen, {}); + ThrowFatalError(system, error_code, FatalType::ErrorScreen, {}); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -141,7 +143,8 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { const auto error_code = rp.Pop<ResultCode>(); const auto fatal_type = rp.PopEnum<FatalType>(); - ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy + ThrowFatalError(system, error_code, fatal_type, + {}); // No info is passed with ThrowFatalWithPolicy IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -157,15 +160,15 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!"); std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo)); - ThrowFatalError(error_code, fatal_type, info); + ThrowFatalError(system, error_code, fatal_type, info); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared<Module>(); - std::make_shared<Fatal_P>(module)->InstallAsService(service_manager); - std::make_shared<Fatal_U>(module)->InstallAsService(service_manager); + std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager); + std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager); } } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index 09371ff7f..bd9339dfc 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h @@ -6,13 +6,17 @@ #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Service::Fatal { class Module final { public: class Interface : public ServiceFramework<Interface> { public: - explicit Interface(std::shared_ptr<Module> module, const char* name); + explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); ~Interface() override; void ThrowFatal(Kernel::HLERequestContext& ctx); @@ -21,9 +25,10 @@ public: protected: std::shared_ptr<Module> module; + Core::System& system; }; }; -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp index 9e5f872ff..066ccf6b0 100644 --- a/src/core/hle/service/fatal/fatal_p.cpp +++ b/src/core/hle/service/fatal/fatal_p.cpp @@ -6,8 +6,8 @@ namespace Service::Fatal { -Fatal_P::Fatal_P(std::shared_ptr<Module> module) - : Module::Interface(std::move(module), "fatal:p") {} +Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system) + : Module::Interface(std::move(module), system, "fatal:p") {} Fatal_P::~Fatal_P() = default; diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h index 6e9c5979f..c6d953cb5 100644 --- a/src/core/hle/service/fatal/fatal_p.h +++ b/src/core/hle/service/fatal/fatal_p.h @@ -10,7 +10,7 @@ namespace Service::Fatal { class Fatal_P final : public Module::Interface { public: - explicit Fatal_P(std::shared_ptr<Module> module); + explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system); ~Fatal_P() override; }; diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index 1572a2051..8d72ed485 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp @@ -6,7 +6,8 @@ namespace Service::Fatal { -Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") { +Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system) + : Module::Interface(std::move(module), system, "fatal:u") { static const FunctionInfo functions[] = { {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h index 72cb6d076..34c5c7f95 100644 --- a/src/core/hle/service/fatal/fatal_u.h +++ b/src/core/hle/service/fatal/fatal_u.h @@ -10,7 +10,7 @@ namespace Service::Fatal { class Fatal_U final : public Module::Interface { public: - explicit Fatal_U(std::shared_ptr<Module> module); + explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system); ~Fatal_U() override; }; diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 14cd0e322..7fa4e820b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -674,6 +674,15 @@ FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) return bis_factory->GetModificationDumpRoot(title_id); } +FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { + LOG_TRACE(Service_FS, "Opening BCAT root for tid={:016X}", title_id); + + if (bis_factory == nullptr) + return nullptr; + + return bis_factory->GetBCATDirectory(title_id); +} + void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { if (overwrite) { bis_factory = nullptr; diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 3e0c03ec0..e6b49d8a2 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -110,6 +110,8 @@ public: FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; + FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; + // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function // above is called. void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index d1ec12ef9..42b4ee861 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -149,7 +149,8 @@ private: class INotificationService final : public ServiceFramework<INotificationService> { public: - INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) { + INotificationService(Common::UUID uuid, Core::System& system) + : ServiceFramework("INotificationService"), uuid(uuid) { // clang-format off static const FunctionInfo functions[] = { {0, &INotificationService::GetEvent, "GetEvent"}, @@ -159,6 +160,9 @@ public: // clang-format on RegisterHandlers(functions); + + notification_event = Kernel::WritableEvent::CreateEventPair( + system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); } private: @@ -167,13 +171,6 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - - if (!is_event_created) { - auto& kernel = Core::System::GetInstance().Kernel(); - notification_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); - is_event_created = true; - } rb.PushCopyObjects(notification_event.readable); } @@ -261,21 +258,21 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<INotificationService>(uuid); + rb.PushIpcInterface<INotificationService>(uuid, system); } -Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) - : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) + : ServiceFramework(name), module(std::move(module)), system(system) {} Module::Interface::~Interface() = default; -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared<Module>(); - std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); - std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager); - std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager); - std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager); - std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager); + std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager); + std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager); + std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager); + std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager); + std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager); } } // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index 38d05fa8e..24f3fc969 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -6,13 +6,17 @@ #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Service::Friend { class Module final { public: class Interface : public ServiceFramework<Interface> { public: - explicit Interface(std::shared_ptr<Module> module, const char* name); + explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); ~Interface() override; void CreateFriendService(Kernel::HLERequestContext& ctx); @@ -20,10 +24,11 @@ public: protected: std::shared_ptr<Module> module; + Core::System& system; }; }; /// Registers all Friend services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::Friend diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 5b384f733..58155f652 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -6,8 +6,8 @@ namespace Service::Friend { -Friend::Friend(std::shared_ptr<Module> module, const char* name) - : Interface(std::move(module), name) { +Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name) + : Interface(std::move(module), system, name) { static const FunctionInfo functions[] = { {0, &Friend::CreateFriendService, "CreateFriendService"}, {1, &Friend::CreateNotificationService, "CreateNotificationService"}, diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h index 1963def39..465a35770 100644 --- a/src/core/hle/service/friend/interface.h +++ b/src/core/hle/service/friend/interface.h @@ -10,7 +10,7 @@ namespace Service::Friend { class Friend final : public Module::Interface { public: - explicit Friend(std::shared_ptr<Module> module, const char* name); + explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name); ~Friend() override; }; diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 0993a7815..8091db9d7 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -6,7 +6,7 @@ namespace Service::HID { -ControllerBase::ControllerBase() = default; +ControllerBase::ControllerBase(Core::System& system) : system(system) {} ControllerBase::~ControllerBase() = default; void ControllerBase::ActivateController() { diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 5e5097a03..8bc69c372 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -11,10 +11,14 @@ namespace Core::Timing { class CoreTiming; } +namespace Core { +class System; +} + namespace Service::HID { class ControllerBase { public: - ControllerBase(); + explicit ControllerBase(Core::System& system); virtual ~ControllerBase(); // Called when the controller is initialized @@ -46,5 +50,7 @@ protected: s64_le entry_count; }; static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index c5c2e032a..8e8263f5b 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -14,7 +14,8 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff; constexpr s32 HID_JOYSTICK_MIN = -0x7fff; enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; -Controller_DebugPad::Controller_DebugPad() = default; +Controller_DebugPad::Controller_DebugPad(Core::System& system) + : ControllerBase(system), system(system) {} Controller_DebugPad::~Controller_DebugPad() = default; void Controller_DebugPad::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index e584b92ec..6c4de817e 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -16,7 +16,7 @@ namespace Service::HID { class Controller_DebugPad final : public ControllerBase { public: - Controller_DebugPad(); + explicit Controller_DebugPad(Core::System& system); ~Controller_DebugPad() override; // Called when the controller is initialized @@ -89,5 +89,6 @@ private: buttons; std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> analogs; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index a179252e3..80da0a0d3 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -10,7 +10,8 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; -Controller_Gesture::Controller_Gesture() = default; +Controller_Gesture::Controller_Gesture(Core::System& system) + : ControllerBase(system), system(system) {} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index f305fe90f..396897527 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -12,7 +12,7 @@ namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: - Controller_Gesture(); + explicit Controller_Gesture(Core::System& system); ~Controller_Gesture() override; // Called when the controller is initialized @@ -59,5 +59,6 @@ private: std::array<GestureState, 17> gesture_states; }; SharedMemory shared_memory{}; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 92d7bfb52..e587b2e15 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,7 +12,8 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; constexpr u8 KEYS_PER_BYTE = 8; -Controller_Keyboard::Controller_Keyboard() = default; +Controller_Keyboard::Controller_Keyboard(Core::System& system) + : ControllerBase(system), system(system) {} Controller_Keyboard::~Controller_Keyboard() = default; void Controller_Keyboard::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 73cd2c7bb..ef586f7eb 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -15,7 +15,7 @@ namespace Service::HID { class Controller_Keyboard final : public ControllerBase { public: - Controller_Keyboard(); + explicit Controller_Keyboard(Core::System& system); ~Controller_Keyboard() override; // Called when the controller is initialized @@ -53,5 +53,6 @@ private: keyboard_keys; std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> keyboard_mods; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 11ab096d9..88f2ca4c1 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -11,7 +11,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse() = default; +Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {} Controller_Mouse::~Controller_Mouse() = default; void Controller_Mouse::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 9d46eecbe..df2da6ae3 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -14,7 +14,7 @@ namespace Service::HID { class Controller_Mouse final : public ControllerBase { public: - Controller_Mouse(); + explicit Controller_Mouse(Core::System& system); ~Controller_Mouse() override; // Called when the controller is initialized @@ -53,5 +53,6 @@ private: std::unique_ptr<Input::MouseDevice> mouse_device; std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> mouse_button_devices; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e47fe8188..a9cd119c4 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -93,7 +93,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) { }; } -Controller_NPad::Controller_NPad() = default; +Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} Controller_NPad::~Controller_NPad() = default; void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { @@ -165,12 +165,15 @@ void Controller_NPad::InitNewlyAddedControler(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(); } void Controller_NPad::OnInit() { - auto& kernel = Core::System::GetInstance().Kernel(); - styleset_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged"); + auto& kernel = system.Kernel(); + for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { + styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Manual, fmt::format("npad:NpadStyleSetChanged_{}", i)); + } if (!IsControllerActivated()) { return; @@ -431,7 +434,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { supported_npad_id_types.clear(); supported_npad_id_types.resize(length / sizeof(u32)); std::memcpy(supported_npad_id_types.data(), data, length); - bool had_controller_update = false; for (std::size_t i = 0; i < connected_controllers.size(); i++) { auto& controller = connected_controllers[i]; if (!controller.is_connected) { @@ -450,10 +452,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { controller.type = requested_controller; InitNewlyAddedControler(i); } - had_controller_update = true; - } - if (had_controller_update) { - styleset_changed_event.writable->Signal(); } } } @@ -468,7 +466,6 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { } void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { - styleset_changed_event.writable->Signal(); hold_type = joy_hold_type; } @@ -479,7 +476,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { const std::size_t npad_index = NPadIdToIndex(npad_id); ASSERT(npad_index < shared_memory_entries.size()); - shared_memory_entries[npad_index].pad_assignment = assignment_mode; + if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { + shared_memory_entries[npad_index].pad_assignment = assignment_mode; + } } void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, @@ -498,11 +497,12 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, last_processed_vibration = vibrations.back(); } -Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const { +Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent( + u32 npad_id) const { // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should // be signalled at least once, and signaled after a new controller is connected? - styleset_changed_event.writable->Signal(); - return styleset_changed_event.readable; + const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; + return styleset_event.readable; } Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index f28b36806..1bc3d55d6 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -20,7 +20,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? class Controller_NPad final : public ControllerBase { public: - Controller_NPad(); + explicit Controller_NPad(Core::System& system); ~Controller_NPad() override; // Called when the controller is initialized @@ -109,7 +109,7 @@ public: void VibrateController(const std::vector<u32>& controller_ids, const std::vector<Vibration>& vibrations); - Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const; + Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; Vibration GetLastVibration() const; void AddNewController(NPadControllerType controller); @@ -315,7 +315,8 @@ private: sticks; std::vector<u32> supported_npad_id_types{}; NpadHoldType hold_type{NpadHoldType::Vertical}; - Kernel::EventPair styleset_changed_event; + // Each controller should have their own styleset changed event + std::array<Kernel::EventPair, 10> styleset_changed_events; Vibration last_processed_vibration{}; std::array<ControllerHolder, 10> connected_controllers{}; bool can_controllers_vibrate{true}; @@ -327,5 +328,6 @@ private: std::array<ControllerPad, 10> npad_pad_states{}; bool IsControllerSupported(NPadControllerType controller); bool is_in_lr_assignment_mode{false}; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 946948f5e..9b829341e 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -9,7 +9,8 @@ namespace Service::HID { -Controller_Stubbed::Controller_Stubbed() = default; +Controller_Stubbed::Controller_Stubbed(Core::System& system) + : ControllerBase(system), system(system) {} Controller_Stubbed::~Controller_Stubbed() = default; void Controller_Stubbed::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 24469f03e..37d7d8538 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -10,7 +10,7 @@ namespace Service::HID { class Controller_Stubbed final : public ControllerBase { public: - Controller_Stubbed(); + explicit Controller_Stubbed(Core::System& system); ~Controller_Stubbed() override; // Called when the controller is initialized @@ -30,5 +30,6 @@ public: private: bool smart_update{}; std::size_t common_offset{}; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 1a8445a43..25912fd69 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -13,7 +13,8 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen() = default; +Controller_Touchscreen::Controller_Touchscreen(Core::System& system) + : ControllerBase(system), system(system) {} Controller_Touchscreen::~Controller_Touchscreen() = default; void Controller_Touchscreen::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 76fc340e9..3429c84db 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -14,7 +14,7 @@ namespace Service::HID { class Controller_Touchscreen final : public ControllerBase { public: - Controller_Touchscreen(); + explicit Controller_Touchscreen(Core::System& system); ~Controller_Touchscreen() override; // Called when the controller is initialized @@ -69,5 +69,6 @@ private: TouchScreenSharedMemory shared_memory{}; std::unique_ptr<Input::TouchDevice> touch_device; s64_le last_touch{}; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 1a9da9576..1bce044b4 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -10,7 +10,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad() = default; +Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {} Controller_XPad::~Controller_XPad() = default; void Controller_XPad::OnInit() {} diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 2864e6617..c445ebec0 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -12,7 +12,7 @@ namespace Service::HID { class Controller_XPad final : public ControllerBase { public: - Controller_XPad(); + explicit Controller_XPad(Core::System& system); ~Controller_XPad() override; // Called when the controller is initialized @@ -56,5 +56,6 @@ private: }; static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); SharedMemory shared_memory{}; + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index f8b1ca816..8d76ba746 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -42,13 +42,14 @@ constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_C constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; -IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { +IAppletResource::IAppletResource(Core::System& system) + : ServiceFramework("IAppletResource"), system(system) { static const FunctionInfo functions[] = { {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, }; RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); shared_mem = Kernel::SharedMemory::Create( kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); @@ -74,7 +75,7 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); // Register update callbacks - auto& core_timing = Core::System::GetInstance().CoreTiming(); + auto& core_timing = system.CoreTiming(); pad_update_event = core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { UpdateControllers(userdata, cycles_late); @@ -96,7 +97,7 @@ void IAppletResource::DeactivateController(HidController controller) { } IAppletResource ::~IAppletResource() { - Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(pad_update_event, 0); } void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { @@ -108,7 +109,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { } void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { - auto& core_timing = Core::System::GetInstance().CoreTiming(); + auto& core_timing = system.CoreTiming(); const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); for (const auto& controller : controllers) { @@ -141,13 +142,13 @@ private: std::shared_ptr<IAppletResource> Hid::GetAppletResource() { if (applet_resource == nullptr) { - applet_resource = std::make_shared<IAppletResource>(); + applet_resource = std::make_shared<IAppletResource>(system); } return applet_resource; } -Hid::Hid() : ServiceFramework("hid") { +Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &Hid::CreateAppletResource, "CreateAppletResource"}, @@ -286,7 +287,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); if (applet_resource == nullptr) { - applet_resource = std::make_shared<IAppletResource>(); + applet_resource = std::make_shared<IAppletResource>(system); } IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -479,7 +480,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetStyleSetChangedEvent()); + .GetStyleSetChangedEvent(npad_id)); } void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { @@ -1053,14 +1054,14 @@ void ReloadInputDevices() { Settings::values.is_device_reload_pending.store(true); } -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<Hid>()->InstallAsService(service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<Hid>(system)->InstallAsService(service_manager); std::make_shared<HidBus>()->InstallAsService(service_manager); std::make_shared<HidDbg>()->InstallAsService(service_manager); std::make_shared<HidSys>()->InstallAsService(service_manager); std::make_shared<HidTmp>()->InstallAsService(service_manager); - std::make_shared<IRS>()->InstallAsService(service_manager); + std::make_shared<IRS>(system)->InstallAsService(service_manager); std::make_shared<IRS_SYS>()->InstallAsService(service_manager); std::make_shared<XCD_SYS>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 2fd6d9fc7..35b663679 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -42,7 +42,7 @@ enum class HidController : std::size_t { class IAppletResource final : public ServiceFramework<IAppletResource> { public: - IAppletResource(); + explicit IAppletResource(Core::System& system); ~IAppletResource() override; void ActivateController(HidController controller); @@ -61,7 +61,7 @@ public: private: template <typename T> void MakeController(HidController controller) { - controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); + controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); @@ -70,6 +70,7 @@ private: Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; Core::Timing::EventType* pad_update_event; + Core::System& system; std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> controllers{}; @@ -77,7 +78,7 @@ private: class Hid final : public ServiceFramework<Hid> { public: - Hid(); + explicit Hid(Core::System& system); ~Hid() override; std::shared_ptr<IAppletResource> GetAppletResource(); @@ -126,12 +127,13 @@ private: void SwapNpadAssignment(Kernel::HLERequestContext& ctx); std::shared_ptr<IAppletResource> applet_resource; + Core::System& system; }; /// Reload input devices. Used when input configuration changed void ReloadInputDevices(); /// Registers all HID services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 2c4625c99..5e79e2c1a 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -11,7 +11,7 @@ namespace Service::HID { -IRS::IRS() : ServiceFramework{"irs"} { +IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) { // clang-format off static const FunctionInfo functions[] = { {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, @@ -37,7 +37,7 @@ IRS::IRS() : ServiceFramework{"irs"} { RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); shared_mem = Kernel::SharedMemory::Create( kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory"); @@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 5}; rb.Push(RESULT_SUCCESS); - rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks()); + rb.PushRaw<u64>(system.CoreTiming().GetTicks()); rb.PushRaw<u32>(0); } diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 12de6bfb3..eb4e898dd 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -15,7 +15,7 @@ namespace Service::HID { class IRS final : public ServiceFramework<IRS> { public: - explicit IRS(); + explicit IRS(Core::System& system); ~IRS() override; private: @@ -39,6 +39,7 @@ private: void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; const u32 device_handle{0xABCD}; + Core::System& system; }; class IRS_SYS final : public ServiceFramework<IRS_SYS> { diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 8ddad8682..3164ca26e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -78,7 +78,7 @@ public: class RelocatableObject final : public ServiceFramework<RelocatableObject> { public: - explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { + explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &RelocatableObject::LoadNro, "LoadNro"}, @@ -364,7 +364,7 @@ public: vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, Kernel::VMAPermission::ReadWrite); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + system.InvalidateCpuInstructionCaches(); nro.insert_or_assign(*map_address, NROInfo{hash, nro_address, nro_size, bss_address, bss_size}); @@ -430,7 +430,7 @@ public: .IsSuccess()); } - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + system.InvalidateCpuInstructionCaches(); nro.erase(iter); IPC::ResponseBuilder rb{ctx, 2}; @@ -516,13 +516,14 @@ private: Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && Common::Is4KBAligned(header.rw_size); } + Core::System& system; }; -void InstallInterfaces(SM::ServiceManager& sm) { +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<DebugMonitor>()->InstallAsService(sm); std::make_shared<ProcessManager>()->InstallAsService(sm); std::make_shared<Shell>()->InstallAsService(sm); - std::make_shared<RelocatableObject>()->InstallAsService(sm); + std::make_shared<RelocatableObject>(system)->InstallAsService(sm); } } // namespace Service::LDR diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h index 412410c4f..7ac8c0b65 100644 --- a/src/core/hle/service/ldr/ldr.h +++ b/src/core/hle/service/ldr/ldr.h @@ -11,6 +11,6 @@ class ServiceManager; namespace Service::LDR { /// Registers all LDR services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& sm); +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); } // namespace Service::LDR diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a5cb06f8a..a42c22d44 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -23,9 +23,9 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); } // namespace ErrCodes -Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) - : ServiceFramework(name), module(std::move(module)) { - auto& kernel = Core::System::GetInstance().Kernel(); +Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) + : ServiceFramework(name), module(std::move(module)), system(system) { + auto& kernel = system.Kernel(); nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IUser:NFCTagDetected"); } @@ -34,8 +34,8 @@ Module::Interface::~Interface() = default; class IUser final : public ServiceFramework<IUser> { public: - IUser(Module::Interface& nfp_interface) - : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { + IUser(Module::Interface& nfp_interface, Core::System& system) + : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) { static const FunctionInfo functions[] = { {0, &IUser::Initialize, "Initialize"}, {1, &IUser::Finalize, "Finalize"}, @@ -65,7 +65,7 @@ public: }; RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); deactivate_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); availability_change_event = Kernel::WritableEvent::CreateEventPair( @@ -324,6 +324,7 @@ private: Kernel::EventPair deactivate_event; Kernel::EventPair availability_change_event; const Module::Interface& nfp_interface; + Core::System& system; }; void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { @@ -331,7 +332,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IUser>(*this); + rb.PushIpcInterface<IUser>(*this, system); } bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { @@ -353,9 +354,9 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const return amiibo; } -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared<Module>(); - std::make_shared<NFP_User>(module)->InstallAsService(service_manager); + std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager); } } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index a1817e991..9718ef745 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -16,7 +16,7 @@ class Module final { public: class Interface : public ServiceFramework<Interface> { public: - explicit Interface(std::shared_ptr<Module> module, const char* name); + explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); ~Interface() override; struct ModelInfo { @@ -43,9 +43,10 @@ public: protected: std::shared_ptr<Module> module; + Core::System& system; }; }; -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 784a87c1b..298184f17 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -6,8 +6,8 @@ namespace Service::NFP { -NFP_User::NFP_User(std::shared_ptr<Module> module) - : Module::Interface(std::move(module), "nfp:user") { +NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system) + : Module::Interface(std::move(module), system, "nfp:user") { static const FunctionInfo functions[] = { {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, }; diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 65d9aaf48..1686ebf20 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h @@ -10,7 +10,7 @@ namespace Service::NFP { class NFP_User final : public Module::Interface { public: - explicit NFP_User(std::shared_ptr<Module> module); + explicit NFP_User(std::shared_ptr<Module> module, Core::System& system); ~NFP_User() override; }; diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 76b12b482..756a2af57 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -12,6 +12,13 @@ namespace Service::NIFM { +enum class RequestState : u32 { + NotSubmitted = 1, + Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW. + Pending = 2, + Connected = 3, +}; + class IScanRequest final : public ServiceFramework<IScanRequest> { public: explicit IScanRequest() : ServiceFramework("IScanRequest") { @@ -31,7 +38,7 @@ public: class IRequest final : public ServiceFramework<IRequest> { public: - explicit IRequest() : ServiceFramework("IRequest") { + explicit IRequest(Core::System& system) : ServiceFramework("IRequest") { static const FunctionInfo functions[] = { {0, &IRequest::GetRequestState, "GetRequestState"}, {1, &IRequest::GetResult, "GetResult"}, @@ -61,7 +68,7 @@ public: }; RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IRequest:Event1"); event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, @@ -81,7 +88,7 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0); + rb.PushEnum(RequestState::Connected); } void GetResult(Kernel::HLERequestContext& ctx) { @@ -130,7 +137,7 @@ public: class IGeneralService final : public ServiceFramework<IGeneralService> { public: - IGeneralService(); + IGeneralService(Core::System& system); private: void GetClientId(Kernel::HLERequestContext& ctx) { @@ -155,7 +162,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IRequest>(); + rb.PushIpcInterface<IRequest>(system); } void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); @@ -189,18 +196,20 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u8>(0); + rb.Push<u8>(1); } void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u8>(0); + rb.Push<u8>(1); } + Core::System& system; }; -IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { +IGeneralService::IGeneralService(Core::System& system) + : ServiceFramework("IGeneralService"), system(system) { static const FunctionInfo functions[] = { {1, &IGeneralService::GetClientId, "GetClientId"}, {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, @@ -245,7 +254,8 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { class NetworkInterface final : public ServiceFramework<NetworkInterface> { public: - explicit NetworkInterface(const char* name) : ServiceFramework{name} { + explicit NetworkInterface(const char* name, Core::System& system) + : ServiceFramework{name}, system(system) { static const FunctionInfo functions[] = { {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, @@ -258,7 +268,7 @@ public: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); + rb.PushIpcInterface<IGeneralService>(system); } void CreateGeneralService(Kernel::HLERequestContext& ctx) { @@ -266,14 +276,17 @@ public: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IGeneralService>(); + rb.PushIpcInterface<IGeneralService>(system); } + +private: + Core::System& system; }; -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<NetworkInterface>("nifm:a")->InstallAsService(service_manager); - std::make_shared<NetworkInterface>("nifm:s")->InstallAsService(service_manager); - std::make_shared<NetworkInterface>("nifm:u")->InstallAsService(service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager); + std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager); + std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager); } } // namespace Service::NIFM diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 4616b3b48..6857e18f9 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h @@ -8,9 +8,13 @@ namespace Service::SM { class ServiceManager; } +namespace Core { +class System; +} + namespace Service::NIFM { /// Registers all NIFM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::NIFM diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index f319a3ca1..75d414952 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -126,7 +126,7 @@ public: class IEnsureNetworkClockAvailabilityService final : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { public: - IEnsureNetworkClockAvailabilityService() + explicit IEnsureNetworkClockAvailabilityService(Core::System& system) : ServiceFramework("IEnsureNetworkClockAvailabilityService") { static const FunctionInfo functions[] = { {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, @@ -139,7 +139,7 @@ public: }; RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); finished_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Automatic, "IEnsureNetworkClockAvailabilityService:FinishEvent"); @@ -200,7 +200,7 @@ private: class NTC final : public ServiceFramework<NTC> { public: - explicit NTC() : ServiceFramework{"ntc"} { + explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, @@ -218,7 +218,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); + rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system); } // TODO(ogniK): Do we need these? @@ -235,13 +235,14 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + Core::System& system; }; -void InstallInterfaces(SM::ServiceManager& sm) { +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<NIM>()->InstallAsService(sm); std::make_shared<NIM_ECA>()->InstallAsService(sm); std::make_shared<NIM_SHP>()->InstallAsService(sm); - std::make_shared<NTC>()->InstallAsService(sm); + std::make_shared<NTC>(system)->InstallAsService(sm); } } // namespace Service::NIM diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h index 2a2a92df0..dbe25dc01 100644 --- a/src/core/hle/service/nim/nim.h +++ b/src/core/hle/service/nim/nim.h @@ -8,8 +8,12 @@ namespace Service::SM { class ServiceManager; } +namespace Core { +class System; +} + namespace Service::NIM { -void InstallInterfaces(SM::ServiceManager& sm); +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); } // namespace Service::NIM diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 13121c4f1..15c156ce1 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -617,7 +617,8 @@ public: } }; -void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) { +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); @@ -628,7 +629,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSyst std::make_shared<NS_SU>()->InstallAsService(service_manager); std::make_shared<NS_VM>()->InstallAsService(service_manager); - std::make_shared<PL_U>(fsc)->InstallAsService(service_manager); + std::make_shared<PL_U>(system)->InstallAsService(service_manager); } } // namespace Service::NS diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index d067e7a9a..13a64ad88 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -97,8 +97,7 @@ private: }; /// Registers all NS services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace NS - } // namespace Service diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 9d49f36e8..7dcdb4a07 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -150,8 +150,9 @@ struct PL_U::Impl { std::vector<FontRegion> shared_font_regions; }; -PL_U::PL_U(FileSystem::FileSystemController& fsc) - : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { +PL_U::PL_U(Core::System& system) + : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) { + static const FunctionInfo functions[] = { {0, &PL_U::RequestLoad, "RequestLoad"}, {1, &PL_U::GetLoadState, "GetLoadState"}, @@ -161,6 +162,9 @@ PL_U::PL_U(FileSystem::FileSystemController& fsc) {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, }; RegisterHandlers(functions); + + auto& fsc = system.GetFileSystemController(); + // Attempt to load shared font data from disk const auto* nand = fsc.GetSystemNANDContents(); std::size_t offset = 0; @@ -325,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { Kernel::MemoryState::Shared); // Create shared font memory object - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); impl->shared_font_mem = Kernel::SharedMemory::Create( kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 35ca424d2..1063f4204 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -17,7 +17,7 @@ namespace NS { class PL_U final : public ServiceFramework<PL_U> { public: - PL_U(FileSystem::FileSystemController& fsc); + explicit PL_U(Core::System& system); ~PL_U() override; private: @@ -30,6 +30,7 @@ private: struct Impl; std::unique_ptr<Impl> impl; + Core::System& system; }; } // namespace NS diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 5b8248433..1b52511a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/service.h" namespace Core { class System; @@ -38,8 +39,9 @@ public: * @param output A buffer where the output data will be written to. * @returns The result code of the ioctl. */ - virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) = 0; + virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) = 0; protected: Core::System& system; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 926a1285d..f764388bc 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -17,8 +17,9 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} nvdisp_disp0 ::~nvdisp_disp0() = default; -u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index e79e490ff..6fcdeee84 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -20,8 +20,9 @@ public: explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); ~nvdisp_disp0() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; /// Performs a screen flip, drawing the buffer pointed to by the handle. void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 24ab3f2e9..6bc053f27 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -26,8 +26,9 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_ : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} nvhost_as_gpu::~nvhost_as_gpu() = default; -u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 30ca5f4c3..169fb8f0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -20,8 +20,9 @@ public: explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); ~nvhost_as_gpu() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 9a66a5f88..ff6b1abae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -19,8 +19,9 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) : nvdevice(system), events_interface{events_interface} {} nvhost_ctrl::~nvhost_ctrl() = default; -u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 14e6e7e57..9898623de 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -17,8 +17,9 @@ public: explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); ~nvhost_ctrl() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 988effd90..389ace76f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -15,14 +15,15 @@ namespace Service::Nvidia::Devices { nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; -u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, + const std::vector<u8>& input2, std::vector<u8>& output, + std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::IocGetCharacteristicsCommand: - return GetCharacteristics(input, output); + return GetCharacteristics(input, output, output2, version); case IoctlCommand::IocGetTPCMasksCommand: return GetTPCMasks(input, output); case IoctlCommand::IocGetActiveSlotMaskCommand: @@ -44,7 +45,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec return 0; } -u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { +u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, + std::vector<u8>& output2, IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -85,7 +87,13 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto params.gc.gr_compbit_store_base_hw = 0x0; params.gpu_characteristics_buf_size = 0xA0; params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) - std::memcpy(output.data(), ¶ms, output.size()); + + if (version == IoctlVersion::Version3) { + std::memcpy(output.data(), input.data(), output.size()); + std::memcpy(output2.data(), ¶ms.gc, output2.size()); + } else { + std::memcpy(output.data(), ¶ms, output.size()); + } return 0; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 2b035ae3f..642b0a2cb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -16,8 +16,9 @@ public: explicit nvhost_ctrl_gpu(Core::System& system); ~nvhost_ctrl_gpu() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { @@ -162,7 +163,8 @@ private: }; static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); - u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); + u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, + std::vector<u8>& output2, IoctlVersion version); u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b4ee2a255..2b8d1bef6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -17,8 +17,9 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} nvhost_gpu::~nvhost_gpu() = default; -u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); @@ -50,7 +51,7 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u return SubmitGPFIFO(input, output); } if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { - return KickoffPB(input, output); + return KickoffPB(input, output, input2, version); } } @@ -173,7 +174,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp return 0; } -u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) { +u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, + const std::vector<u8>& input2, IoctlVersion version) { if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); } @@ -183,9 +185,13 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) params.num_entries, params.flags.raw); Tegra::CommandList entries(params.num_entries); - Memory::ReadBlock(params.address, entries.data(), - params.num_entries * sizeof(Tegra::CommandListHeader)); - + if (version == IoctlVersion::Version2) { + std::memcpy(entries.data(), input2.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); + } else { + Memory::ReadBlock(params.address, entries.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); + } UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index d2e8fbae9..d056dd046 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -24,8 +24,9 @@ public: explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); ~nvhost_gpu() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { @@ -183,7 +184,8 @@ private: u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); - u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output); + u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, + const std::vector<u8>& input2, IoctlVersion version); u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f572ad30f..bdae8b887 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} nvhost_nvdec::~nvhost_nvdec() = default; -u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 2710f0511..cbdac8069 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -16,8 +16,9 @@ public: explicit nvhost_nvdec(Core::System& system); ~nvhost_nvdec() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 38282956f..96e7b7dab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} nvhost_nvjpg::~nvhost_nvjpg() = default; -u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 379766693..98dcac52f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -16,8 +16,9 @@ public: explicit nvhost_nvjpg(Core::System& system); ~nvhost_nvjpg() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 70e8091db..c695b8863 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} nvhost_vic::~nvhost_vic() = default; -u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 7d111977e..bec32bea1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -16,8 +16,9 @@ public: explicit nvhost_vic(Core::System& system); ~nvhost_vic() override; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; private: enum class IoctlCommand : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 223b496b7..8c742316c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -28,8 +28,9 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { return object->addr; } -u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { switch (static_cast<IoctlCommand>(command.raw)) { case IoctlCommand::Create: return IocCreate(input, output); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index bf4a101c2..73c2e8809 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -22,8 +22,9 @@ public: /// Returns the allocated address of an nvmap object given its handle. VAddr GetObjectAddress(u32 handle) const; - u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) override; + u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) override; /// Represents an nvmap object. struct Object { diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index d5be64ed2..5e0c23602 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -33,42 +33,77 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); } -void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); - +void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { IPC::RequestParser rp{ctx}; u32 fd = rp.Pop<u32>(); u32 command = rp.Pop<u32>(); - std::vector<u8> output(ctx.GetWriteBufferSize()); + /// Ioctl 3 has 2 outputs, first in the input params, second is the result + std::vector<u8> output(ctx.GetWriteBufferSize(0)); + std::vector<u8> output2; + if (version == IoctlVersion::Version3) { + output2.resize((ctx.GetWriteBufferSize(1))); + } + + /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. + /// KickOfPB uses this + auto input = ctx.ReadBuffer(0); + + std::vector<u8> input2; + if (version == IoctlVersion::Version2) { + input2 = ctx.ReadBuffer(1); + } IoctlCtrl ctrl{}; - u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output, ctrl); + u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); if (ctrl.must_delay) { ctrl.fresh_call = false; - ctx.SleepClientThread( - "NVServices::DelayedResponse", ctrl.timeout, - [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, - Kernel::ThreadWakeupReason reason) { - IoctlCtrl ctrl2{ctrl}; - std::vector<u8> output2 = output; - u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output2, ctrl2); - ctx.WriteBuffer(output2); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(result); - }, - nvdrv->GetEventWriteable(ctrl.event_id)); + ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout, + [=](Kernel::SharedPtr<Kernel::Thread> thread, + Kernel::HLERequestContext& ctx, + Kernel::ThreadWakeupReason reason) { + IoctlCtrl ctrl2{ctrl}; + std::vector<u8> tmp_output = output; + std::vector<u8> tmp_output2 = output2; + u32 result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, + tmp_output2, ctrl2, version); + ctx.WriteBuffer(tmp_output, 0); + if (version == IoctlVersion::Version3) { + ctx.WriteBuffer(tmp_output2, 1); + } + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(result); + }, + nvdrv->GetEventWriteable(ctrl.event_id)); } else { ctx.WriteBuffer(output); + if (version == IoctlVersion::Version3) { + ctx.WriteBuffer(output2, 1); + } } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(result); } +void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NVDRV, "called"); + IoctlBase(ctx, IoctlVersion::Version1); +} + +void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NVDRV, "called"); + IoctlBase(ctx, IoctlVersion::Version2); +} + +void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NVDRV, "called"); + IoctlBase(ctx, IoctlVersion::Version3); +} + void NVDRV::Close(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NVDRV, "called"); @@ -154,8 +189,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) {8, &NVDRV::SetClientPID, "SetClientPID"}, {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, {10, nullptr, "InitializeDevtools"}, - {11, &NVDRV::Ioctl, "Ioctl2"}, - {12, nullptr, "Ioctl3"}, + {11, &NVDRV::Ioctl2, "Ioctl2"}, + {12, &NVDRV::Ioctl3, "Ioctl3"}, {13, &NVDRV::FinishInitialize, "FinishInitialize"}, }; RegisterHandlers(functions); diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 10a0ecd52..9269ce00c 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -24,6 +24,8 @@ public: private: void Open(Kernel::HLERequestContext& ctx); void Ioctl(Kernel::HLERequestContext& ctx); + void Ioctl2(Kernel::HLERequestContext& ctx); + void Ioctl3(Kernel::HLERequestContext& ctx); void Close(Kernel::HLERequestContext& ctx); void Initialize(Kernel::HLERequestContext& ctx); void QueryEvent(Kernel::HLERequestContext& ctx); @@ -31,6 +33,7 @@ private: void FinishInitialize(Kernel::HLERequestContext& ctx); void GetStatus(Kernel::HLERequestContext& ctx); void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); + void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); std::shared_ptr<Module> nvdrv; diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index ac03cbc23..529b03471 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -34,6 +34,12 @@ enum class EventState { Busy = 3, }; +enum class IoctlVersion : u32 { + Version1, + Version2, + Version3, +}; + struct IoctlCtrl { // First call done to the servioce for services that call itself again after a call. bool fresh_call{true}; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 2011a226a..307a7e928 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -71,13 +71,14 @@ u32 Module::Open(const std::string& device_name) { return fd; } -u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl) { +u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version) { auto itr = open_files.find(fd); ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); auto& device = itr->second; - return device->ioctl({command}, input, output, ctrl); + return device->ioctl({command}, input, input2, output, output2, ctrl, version); } ResultCode Module::Close(u32 fd) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a339ab672..f8bb28969 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -106,8 +106,9 @@ public: /// Opens a device node and returns a file descriptor to it. u32 Open(const std::string& device_name); /// Sends an ioctl command to the specified file descriptor. - u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, - IoctlCtrl& ctrl); + u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, + std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, + IoctlVersion version); /// Closes a device file descriptor and returns operation success. ResultCode Close(u32 fd); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index f9db79370..2e4d707b9 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -29,26 +29,28 @@ namespace Service::NVFlinger { constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); -NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { - displays.emplace_back(0, "Default"); - displays.emplace_back(1, "External"); - displays.emplace_back(2, "Edid"); - displays.emplace_back(3, "Internal"); - displays.emplace_back(4, "Null"); +NVFlinger::NVFlinger(Core::System& system) : system(system) { + displays.emplace_back(0, "Default", system); + displays.emplace_back(1, "External", system); + displays.emplace_back(2, "Edid", system); + displays.emplace_back(3, "Internal", system); + displays.emplace_back(4, "Null", system); // Schedule the screen composition events - composition_event = core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, - s64 cycles_late) { - Compose(); - const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); - this->core_timing.ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), composition_event); - }); - - core_timing.ScheduleEvent(frame_ticks, composition_event); + composition_event = system.CoreTiming().RegisterEvent( + "ScreenComposition", [this](u64 userdata, s64 cycles_late) { + Compose(); + const auto ticks = + Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); + this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), + composition_event); + }); + + system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); } NVFlinger::~NVFlinger() { - core_timing.UnscheduleEvent(composition_event, 0); + system.CoreTiming().UnscheduleEvent(composition_event, 0); } void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { @@ -185,11 +187,9 @@ void NVFlinger::Compose() { MicroProfileFlip(); if (!buffer) { - auto& system_instance = Core::System::GetInstance(); - // There was no queued buffer to draw, render previous frame - system_instance.GetPerfStats().EndGameFrame(); - system_instance.GPU().SwapBuffers({}); + system.GetPerfStats().EndGameFrame(); + system.GPU().SwapBuffers({}); continue; } diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 988be8726..5d7e3bfb8 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -38,7 +38,7 @@ class BufferQueue; class NVFlinger final { public: - explicit NVFlinger(Core::Timing::CoreTiming& core_timing); + explicit NVFlinger(Core::System& system); ~NVFlinger(); /// Sets the NVDrv module instance to use to send buffers to the GPU. @@ -105,8 +105,7 @@ private: /// Event that handles screen composition. Core::Timing::EventType* composition_event; - /// Core timing instance for registering/unregistering the composition event. - Core::Timing::CoreTiming& core_timing; + Core::System& system; }; } // namespace Service::NVFlinger diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 0f79135ff..18d895263 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -15,7 +15,7 @@ namespace Service::PlayReport { class PlayReport final : public ServiceFramework<PlayReport> { public: - explicit PlayReport(Core::System& system, const char* name) + explicit PlayReport(const char* name, Core::System& system) : ServiceFramework{name}, system(system) { // clang-format off static const FunctionInfo functions[] = { @@ -128,12 +128,12 @@ private: Core::System& system; }; -void InstallInterfaces(Core::System& system) { - std::make_shared<PlayReport>(system, "prepo:a")->InstallAsService(system.ServiceManager()); - std::make_shared<PlayReport>(system, "prepo:a2")->InstallAsService(system.ServiceManager()); - std::make_shared<PlayReport>(system, "prepo:m")->InstallAsService(system.ServiceManager()); - std::make_shared<PlayReport>(system, "prepo:s")->InstallAsService(system.ServiceManager()); - std::make_shared<PlayReport>(system, "prepo:u")->InstallAsService(system.ServiceManager()); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<PlayReport>("prepo:a", system)->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:a2", system)->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:m", system)->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:s", system)->InstallAsService(service_manager); + std::make_shared<PlayReport>("prepo:u", system)->InstallAsService(service_manager); } } // namespace Service::PlayReport diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h index 0ebc3a938..a5682ee26 100644 --- a/src/core/hle/service/prepo/prepo.h +++ b/src/core/hle/service/prepo/prepo.h @@ -8,8 +8,12 @@ namespace Service::SM { class ServiceManager; } +namespace Core { +class System; +} + namespace Service::PlayReport { -void InstallInterfaces(Core::System& system); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::PlayReport diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 906fdc415..f2c6fe9dc 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -198,50 +198,50 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co 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 // here and pass it into the respective InstallInterfaces functions. - auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); + auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); SM::ServiceManager::InstallInterfaces(sm); Account::InstallInterfaces(system); AM::InstallInterfaces(*sm, nv_flinger, system); - AOC::InstallInterfaces(*sm); + AOC::InstallInterfaces(*sm, system); APM::InstallInterfaces(system); Audio::InstallInterfaces(*sm, system); - BCAT::InstallInterfaces(*sm); + BCAT::InstallInterfaces(system); BPC::InstallInterfaces(*sm); - BtDrv::InstallInterfaces(*sm); - BTM::InstallInterfaces(*sm); + BtDrv::InstallInterfaces(*sm, system); + BTM::InstallInterfaces(*sm, system); Capture::InstallInterfaces(*sm); ERPT::InstallInterfaces(*sm); ES::InstallInterfaces(*sm); EUPLD::InstallInterfaces(*sm); - Fatal::InstallInterfaces(*sm); + Fatal::InstallInterfaces(*sm, system); FGM::InstallInterfaces(*sm); FileSystem::InstallInterfaces(system); - Friend::InstallInterfaces(*sm); + Friend::InstallInterfaces(*sm, system); Glue::InstallInterfaces(system); GRC::InstallInterfaces(*sm); - HID::InstallInterfaces(*sm); + HID::InstallInterfaces(*sm, system); LBL::InstallInterfaces(*sm); LDN::InstallInterfaces(*sm); - LDR::InstallInterfaces(*sm); + LDR::InstallInterfaces(*sm, system); LM::InstallInterfaces(*sm); Migration::InstallInterfaces(*sm); Mii::InstallInterfaces(*sm); MM::InstallInterfaces(*sm); NCM::InstallInterfaces(*sm); NFC::InstallInterfaces(*sm); - NFP::InstallInterfaces(*sm); - NIFM::InstallInterfaces(*sm); - NIM::InstallInterfaces(*sm); + NFP::InstallInterfaces(*sm, system); + NIFM::InstallInterfaces(*sm, system); + NIM::InstallInterfaces(*sm, system); NPNS::InstallInterfaces(*sm); - NS::InstallInterfaces(*sm, system.GetFileSystemController()); + NS::InstallInterfaces(*sm, system); Nvidia::InstallInterfaces(*sm, *nv_flinger, system); PCIe::InstallInterfaces(*sm); PCTL::InstallInterfaces(*sm); PCV::InstallInterfaces(*sm); - PlayReport::InstallInterfaces(system); + PlayReport::InstallInterfaces(*sm, system); PM::InstallInterfaces(system); PSC::InstallInterfaces(*sm); PSM::InstallInterfaces(*sm); diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 1030185e0..9565e7de5 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -7,8 +7,8 @@ namespace Service::Time { Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, - const char* name) - : Module::Interface(std::move(time), std::move(shared_memory), name) { + Core::System& system, const char* name) + : Module::Interface(std::move(time), std::move(shared_memory), system, name) { // clang-format off static const FunctionInfo functions[] = { {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index bdf0883e2..5c63a07f4 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h @@ -13,7 +13,7 @@ class SharedMemory; class Time final : public Module::Interface { public: explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, - const char* name); + Core::System& system, const char* name); ~Time() override; }; diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index ae6446204..1b9ab8401 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -126,8 +126,8 @@ private: class ISteadyClock final : public ServiceFramework<ISteadyClock> { public: - ISteadyClock(std::shared_ptr<SharedMemory> shared_memory) - : ServiceFramework("ISteadyClock"), shared_memory(shared_memory) { + ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system) + : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) { static const FunctionInfo functions[] = { {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, }; @@ -150,12 +150,13 @@ private: } SteadyClockTimePoint GetCurrentTimePoint() const { - const auto& core_timing = Core::System::GetInstance().CoreTiming(); + const auto& core_timing = system.CoreTiming(); const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); return {static_cast<u64_le>(ms.count() / 1000), {}}; } std::shared_ptr<SharedMemory> shared_memory; + Core::System& system; }; class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { @@ -290,7 +291,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISteadyClock>(shared_memory); + rb.PushIpcInterface<ISteadyClock>(shared_memory, system); } void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { @@ -325,7 +326,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { return; } - const auto& core_timing = Core::System::GetInstance().CoreTiming(); + const auto& core_timing = system.CoreTiming(); const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; @@ -407,8 +408,10 @@ void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled( } Module::Interface::Interface(std::shared_ptr<Module> time, - std::shared_ptr<SharedMemory> shared_memory, const char* name) - : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {} + std::shared_ptr<SharedMemory> shared_memory, Core::System& system, + const char* name) + : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)), + system(system) {} Module::Interface::~Interface() = default; @@ -416,9 +419,11 @@ void InstallInterfaces(Core::System& system) { auto time = std::make_shared<Module>(); auto shared_mem = std::make_shared<SharedMemory>(system); - std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager()); - std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager()); - std::make_shared<Time>(std::move(time), shared_mem, "time:u") + std::make_shared<Time>(time, shared_mem, system, "time:a") + ->InstallAsService(system.ServiceManager()); + std::make_shared<Time>(time, shared_mem, system, "time:s") + ->InstallAsService(system.ServiceManager()); + std::make_shared<Time>(std::move(time), shared_mem, system, "time:u") ->InstallAsService(system.ServiceManager()); } diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index e0708f856..c32d32860 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -80,7 +80,8 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> time, - std::shared_ptr<SharedMemory> shared_memory, const char* name); + std::shared_ptr<SharedMemory> shared_memory, Core::System& system, + const char* name); ~Interface() override; void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); @@ -97,6 +98,7 @@ public: protected: std::shared_ptr<Module> time; std::shared_ptr<SharedMemory> shared_memory; + Core::System& system; }; }; diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index a8d088305..006a6d9ff 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -15,8 +15,8 @@ namespace Service::VI { -Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} { - auto& kernel = Core::System::GetInstance().Kernel(); +Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { + auto& kernel = system.Kernel(); vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, fmt::format("Display VSync Event {}", id)); } diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 2acd46ff8..f56b5badc 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -26,7 +26,7 @@ public: /// @param id The unique ID for this display. /// @param name The name for this display. /// - Display(u64 id, std::string name); + Display(u64 id, std::string name, Core::System& system); ~Display(); Display(const Display&) = delete; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index e75c700ad..f629892ae 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -150,6 +150,7 @@ 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()) { system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 7de3fd1e5..d1fc94060 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -103,6 +103,8 @@ void LogSettings() { LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); LogSetting("Debugging_ProgramArgs", Settings::values.program_args); + LogSetting("Services_BCATBackend", Settings::values.bcat_backend); + LogSetting("Services_BCATBoxcatLocal", Settings::values.bcat_boxcat_local); } } // namespace Settings diff --git a/src/core/settings.h b/src/core/settings.h index 47bddfb30..9c98a9287 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -448,6 +448,10 @@ struct Values { bool reporting_services; bool quest_flag; + // BCAT + std::string bcat_backend; + bool bcat_boxcat_local; + // WebService bool enable_telemetry; std::string web_api_url; |