diff options
Diffstat (limited to 'src/core/hle/service')
74 files changed, 2350 insertions, 703 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 0c0f7ed6e..7e3e311fb 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -84,7 +84,7 @@ protected: LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Get actual error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code } } @@ -98,7 +98,7 @@ protected: } else { LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Get actual error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code } } @@ -442,7 +442,7 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex const auto user_list = profile_manager->GetAllUsers(); if (std::all_of(user_list.begin(), user_list.end(), [](const auto& user) { return user.uuid == Common::INVALID_UUID; })) { - rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find the correct error code rb.PushRaw<u128>(Common::INVALID_UUID); return; } diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 8f9986326..3e756e59e 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -31,8 +31,8 @@ struct ProfileDataRaw { static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); // TODO(ogniK): Get actual error codes -constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); -constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2); +constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, u32(-1)); +constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, u32(-2)); constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/"; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 797c9a06f..701f05019 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_} { @@ -283,8 +289,8 @@ ISelfController::ISelfController(Core::System& system, RegisterHandlers(functions); auto& kernel = system.Kernel(); - launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, - "ISelfController:LaunchableEvent"); + launchable_event = + Kernel::WritableEvent::CreateEventPair(kernel, "ISelfController:LaunchableEvent"); // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple @@ -292,7 +298,7 @@ ISelfController::ISelfController(Core::System& system, // suspended if the event has previously been created by a call to // GetAccumulatedSuspendedTickChangedEvent. accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent"); + kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent"); accumulated_suspended_tick_changed_event.writable->Signal(); } @@ -517,10 +523,10 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest } AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { - on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, - "AMMessageQueue:OnMessageRecieved"); - on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "AMMessageQueue:OperationModeChanged"); + on_new_message = + Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageRecieved"); + on_operation_mode_changed = + Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged"); } AppletMessageQueue::~AppletMessageQueue() = default; @@ -985,7 +991,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -1021,7 +1027,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex if (transfer_mem == nullptr) { LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -1067,10 +1073,11 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {71, nullptr, "RequestToReboot"}, {80, nullptr, "ExitAndRequestToShowThanksMessage"}, {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, - {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, - {101, nullptr, "SetApplicationCopyrightImage"}, - {102, nullptr, "SetApplicationCopyrightVisibility"}, - {110, nullptr, "QueryApplicationPlayStatistics"}, + {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, + {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, + {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, + {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, + {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, @@ -1085,7 +1092,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) auto& kernel = system.Kernel(); gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); + kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); } IApplicationFunctions::~IApplicationFunctions() = default; @@ -1097,6 +1104,31 @@ void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestConte rb.Push(RESULT_SUCCESS); } +void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer( + Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void IApplicationFunctions::SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void IApplicationFunctions::SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_visible = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -1128,26 +1160,56 @@ 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>(); + + LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); + + if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { + const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) { + return system.GetFileSystemController().GetBCATDirectory(tid); + }); + const auto build_id_full = system.GetCurrentProcessBuildID(); + u64 build_id{}; + std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); + + const auto data = + backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); + + 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{}; - LaunchParameters params{}; + params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; + params.is_account_selected = 1; - params.magic = POP_LAUNCH_PARAMETER_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; - Account::ProfileManager profile_manager{}; - const auto uuid = profile_manager.GetUser(Settings::values.current_user); - ASSERT(uuid); - params.current_user = uuid->uuid; + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); - rb.Push(RESULT_SUCCESS); + std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), ¶ms, buffer.size()); - std::vector<u8> buffer(sizeof(LaunchParameters)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); + rb.PushIpcInterface<AM::IStorage>(buffer); + launch_popped_account_preselect = true; + return; + } - rb.PushIpcInterface<AM::IStorage>(buffer); + 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( @@ -1165,7 +1227,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); FileSys::SaveDataDescriptor descriptor{}; - descriptor.title_id = Core::CurrentProcess()->GetTitleID(); + descriptor.title_id = system.CurrentProcess()->GetTitleID(); descriptor.user_id = user_id; descriptor.type = FileSys::SaveDataType::SaveData; const auto res = system.GetFileSystemController().CreateSaveData( @@ -1274,12 +1336,16 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { } void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + u64 new_normal_size; + u64 new_journal_size; + }; + static_assert(sizeof(Parameters) == 40); + IPC::RequestParser rp{ctx}; - const auto type{rp.PopRaw<FileSys::SaveDataType>()}; - rp.Skip(1, false); - const auto user_id{rp.PopRaw<u128>()}; - const auto new_normal_size{rp.PopRaw<u64>()}; - const auto new_journal_size{rp.PopRaw<u64>()}; + const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>(); LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " @@ -1298,10 +1364,14 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { } void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + }; + static_assert(sizeof(Parameters) == 24); + IPC::RequestParser rp{ctx}; - const auto type{rp.PopRaw<FileSys::SaveDataType>()}; - rp.Skip(1, false); - const auto user_id{rp.PopRaw<u128>()}; + const auto [type, user_id] = rp.PopRaw<Parameters>(); LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), user_id[1], user_id[0]); @@ -1315,6 +1385,22 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { rb.Push(size.journal); } +void IApplicationFunctions::QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); +} + +void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); +} + void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index a3baeb673..06a65b5ed 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -147,6 +147,7 @@ private: void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); + Core::System& system; std::shared_ptr<NVFlinger::NVFlinger> nvflinger; Kernel::EventPair launchable_event; Kernel::EventPair accumulated_suspended_tick_changed_event; @@ -154,8 +155,6 @@ 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> { @@ -253,8 +252,15 @@ private: void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); + void InitializeApplicationCopyrightFrameBuffer(Kernel::HLERequestContext& ctx); + void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx); + void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); + void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); + void QueryApplicationPlayStatisticsByUid(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/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index d2e35362f..673ad1f7f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -24,12 +24,12 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { - state_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopDataOutEvent"); + state_changed_event = + Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:StateChangedEvent"); + pop_out_data_event = + Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); + kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } AppletDataBroker::~AppletDataBroker() = default; @@ -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/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index a7db26725..eab0d42c9 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -20,9 +20,9 @@ namespace Service::AM::Applets { struct ShowError { u8 mode; bool jump; - INSERT_PADDING_BYTES(4); + INSERT_UNION_PADDING_BYTES(4); bool use_64bit_error_code; - INSERT_PADDING_BYTES(1); + INSERT_UNION_PADDING_BYTES(1); u64 error_code_64; u32 error_code_32; }; @@ -32,7 +32,7 @@ static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); struct ShowErrorRecord { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u64 error_code_64; u64 posix_time; }; @@ -41,7 +41,7 @@ static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect si struct SystemErrorArg { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u64 error_code_64; std::array<char, 8> language_code; std::array<char, 0x800> main_text; @@ -52,7 +52,7 @@ static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect si struct ApplicationErrorArg { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u32 error_code; std::array<char, 8> language_code; std::array<char, 0x800> main_text; @@ -65,6 +65,7 @@ union Error::ErrorArguments { ShowErrorRecord error_record; SystemErrorArg system_error; ApplicationErrorArg application_error; + std::array<u8, 0x1018> raw{}; }; namespace { diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 32283e819..5546ef6e8 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -337,7 +337,7 @@ void WebBrowser::ExecuteInternal() { void WebBrowser::InitializeShop() { if (frontend_e_commerce == nullptr) { LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -353,7 +353,7 @@ void WebBrowser::InitializeShop() { if (url == args.end()) { LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -366,7 +366,7 @@ void WebBrowser::InitializeShop() { // Less is missing info, More is malformed if (split_query.size() != 2) { LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -390,7 +390,7 @@ void WebBrowser::InitializeShop() { if (scene == shop_query.end()) { LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -406,7 +406,7 @@ void WebBrowser::InitializeShop() { const auto target = target_map.find(scene->second); if (target == target_map.end()) { LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -427,7 +427,7 @@ void WebBrowser::InitializeOffline() { if (args.find(WebArgTLVType::DocumentPath) == args.end() || args.find(WebArgTLVType::DocumentKind) == args.end() || args.find(WebArgTLVType::ApplicationID) == args.end()) { - status = ResultCode(-1); + status = RESULT_UNKNOWN; LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!"); } @@ -476,7 +476,7 @@ void WebBrowser::InitializeOffline() { offline_romfs = GetApplicationRomFS(system, title_id, type); if (offline_romfs == nullptr) { - status = ResultCode(-1); + status = RESULT_UNKNOWN; LOG_ERROR(Service_AM, "Failed to find offline data for request!"); } @@ -496,7 +496,7 @@ void WebBrowser::ExecuteShop() { const auto check_optional_parameter = [this](const auto& p) { if (!p.has_value()) { LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return false; } diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index e9cf1e840..30076a53e 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -67,8 +67,8 @@ AOC_U::AOC_U(Core::System& system) RegisterHandlers(functions); auto& kernel = system.Kernel(); - aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, - "GetAddOnContentListChanged:Event"); + aoc_change_event = + Kernel::WritableEvent::CreateEventPair(kernel, "GetAddOnContentListChanged:Event"); } AOC_U::~AOC_U() = default; @@ -131,7 +131,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { if (out.size() < offset) { IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find the correct error code. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp index 4376612eb..25a886238 100644 --- a/src/core/hle/service/apm/controller.cpp +++ b/src/core/hle/service/apm/controller.cpp @@ -2,6 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> +#include <array> +#include <utility> + #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/service/apm/controller.h" @@ -9,11 +13,10 @@ namespace Service::APM { -constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION = - PerformanceConfiguration::Config7; +constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7; Controller::Controller(Core::Timing::CoreTiming& core_timing) - : core_timing(core_timing), configs{ + : core_timing{core_timing}, configs{ {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, } {} @@ -22,18 +25,35 @@ Controller::~Controller() = default; void Controller::SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config) { - static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{ - {PerformanceConfiguration::Config1, 1020}, {PerformanceConfiguration::Config2, 1020}, - {PerformanceConfiguration::Config3, 1224}, {PerformanceConfiguration::Config4, 1020}, - {PerformanceConfiguration::Config5, 1020}, {PerformanceConfiguration::Config6, 1224}, - {PerformanceConfiguration::Config7, 1020}, {PerformanceConfiguration::Config8, 1020}, - {PerformanceConfiguration::Config9, 1020}, {PerformanceConfiguration::Config10, 1020}, - {PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020}, - {PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785}, - {PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020}, - }; - - SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second); + static constexpr std::array<std::pair<PerformanceConfiguration, u32>, 16> config_to_speed{{ + {PerformanceConfiguration::Config1, 1020}, + {PerformanceConfiguration::Config2, 1020}, + {PerformanceConfiguration::Config3, 1224}, + {PerformanceConfiguration::Config4, 1020}, + {PerformanceConfiguration::Config5, 1020}, + {PerformanceConfiguration::Config6, 1224}, + {PerformanceConfiguration::Config7, 1020}, + {PerformanceConfiguration::Config8, 1020}, + {PerformanceConfiguration::Config9, 1020}, + {PerformanceConfiguration::Config10, 1020}, + {PerformanceConfiguration::Config11, 1020}, + {PerformanceConfiguration::Config12, 1020}, + {PerformanceConfiguration::Config13, 1785}, + {PerformanceConfiguration::Config14, 1785}, + {PerformanceConfiguration::Config15, 1020}, + {PerformanceConfiguration::Config16, 1020}, + }}; + + const auto iter = std::find_if(config_to_speed.cbegin(), config_to_speed.cend(), + [config](const auto& entry) { return entry.first == config; }); + + if (iter == config_to_speed.cend()) { + LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", + static_cast<u32>(config)); + return; + } + + SetClockSpeed(iter->second); configs.insert_or_assign(mode, config); } @@ -48,7 +68,7 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode))); } -PerformanceMode Controller::GetCurrentPerformanceMode() { +PerformanceMode Controller::GetCurrentPerformanceMode() const { return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; } @@ -63,6 +83,7 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa void Controller::SetClockSpeed(u32 mhz) { LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); // TODO(DarkLordZach): Actually signal core_timing to change clock speed. + // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. } } // namespace Service::APM diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h index 8ac80eaea..af0c4cd34 100644 --- a/src/core/hle/service/apm/controller.h +++ b/src/core/hle/service/apm/controller.h @@ -50,21 +50,21 @@ enum class PerformanceMode : u8 { // system during times of high load -- this simply maps to different PerformanceConfigs to use. class Controller { public: - Controller(Core::Timing::CoreTiming& core_timing); + explicit Controller(Core::Timing::CoreTiming& core_timing); ~Controller(); void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); void SetFromCpuBoostMode(CpuBoostMode mode); - PerformanceMode GetCurrentPerformanceMode(); + PerformanceMode GetCurrentPerformanceMode() const; PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode); private: void SetClockSpeed(u32 mhz); - std::map<PerformanceMode, PerformanceConfiguration> configs; + [[maybe_unused]] Core::Timing::CoreTiming& core_timing; - Core::Timing::CoreTiming& core_timing; + std::map<PerformanceMode, PerformanceConfiguration> configs; }; } // namespace Service::APM diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index fb84a8f13..6a29377e3 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -65,8 +65,8 @@ public: RegisterHandlers(functions); // This is the event handle used to check if the audio buffer was released - buffer_event = Kernel::WritableEvent::CreateEventPair( - system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased"); + buffer_event = + Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, audio_params.channel_count, std::move(unique_name), @@ -205,7 +205,7 @@ private: AudioCore::StreamPtr stream; std::string device_name; - AudoutParams audio_params{}; + [[maybe_unused]] AudoutParams audio_params {}; /// This is the event handle used to check if the audio buffer was released Kernel::EventPair buffer_event; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index f162249ed..4ea7ade6e 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -47,8 +47,8 @@ public: // clang-format on RegisterHandlers(functions); - system_event = Kernel::WritableEvent::CreateEventPair( - system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent"); + system_event = + Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); renderer = std::make_unique<AudioCore::AudioRenderer>( system.CoreTiming(), audren_params, system_event.writable, instance_number); } @@ -180,17 +180,17 @@ public: RegisterHandlers(functions); auto& kernel = system.Kernel(); - buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "IAudioOutBufferReleasedEvent"); + buffer_event = + Kernel::WritableEvent::CreateEventPair(kernel, "IAudioOutBufferReleasedEvent"); // Should be similar to audio_output_device_switch_event audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioInputDeviceSwitchedEvent"); + kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent"); // Should only be signalled when an audio output device has been changed, example: speaker // to headset audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioOutputDeviceSwitchedEvent"); + kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent"); } private: diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index cb4a1160d..cb839e4a2 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -80,7 +80,7 @@ private: LOG_ERROR(Audio, "Failed to decode opus data"); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -278,7 +278,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } 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..dec0849b8 --- /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(Kernel::KernelCore& kernel, + std::string_view event_name) { + event = Kernel::WritableEvent::CreateEventPair( + kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name)); +} + +Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { + 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(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..ea4b16ad0 --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.h @@ -0,0 +1,158 @@ +// 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 <string> +#include <string_view> + +#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 Core { +class System; +} + +namespace Kernel { +class KernelCore; +} + +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(Kernel::KernelCore& kernel, std::string_view event_name); + + Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const; + 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(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(Core::System& system, 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..67e39a5c4 --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -0,0 +1,513 @@ +// 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; +[[maybe_unused]] 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(const AM::Applets::AppletManager& applet_manager, + 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{applet_manager.GetAppletFrontendSet()}; + frontend.error->ShowCustomErrorText( + RESULT_UNKNOWN, "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_ret(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(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter) + : Backend(std::move(getter)), applet_manager{applet_manager_} {} + +Boxcat::~Boxcat() = default; + +void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, 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(applet_manager, 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(applet_manager, 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(applet_manager, 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(applet_manager, 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& error) { + LOG_ERROR(Service_BCAT, "{}", error.what()); + 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..d65b42e58 --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.h @@ -0,0 +1,64 @@ +// 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::AM::Applets { +class AppletManager; +} + +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(AM::Applets::AppletManager& applet_manager, + DirectoryGetter dir_getter, TitleIDVersion title, + ProgressServiceBackend& progress, + std::optional<std::string> dir_name); + +public: + explicit Boxcat(AM::Applets::AppletManager& applet_manager_, 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; + AM::Applets::AppletManager& applet_manager; +}; + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 179aa4949..8bb2528c9 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp @@ -6,11 +6,16 @@ namespace Service::BCAT { -BCAT::BCAT(std::shared_ptr<Module> module, const char* name) - : Module::Interface(std::move(module), name) { +BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module, + FileSystem::FileSystemController& fsc, const char* name) + : Interface(system, 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..6354465fc 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h @@ -6,11 +6,16 @@ #include "core/hle/service/bcat/module.h" +namespace Core { +class System; +} + namespace Service::BCAT { class BCAT final : public Module::Interface { public: - explicit BCAT(std::shared_ptr<Module> module, const char* name); + explicit BCAT(Core::System& system, 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..8a7304f86 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -2,34 +2,258 @@ // 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 Core::System::CurrentBuildProcessID& id) { + 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_ret(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") { + explicit IBcatService(Core::System& system_, Backend& backend_) + : ServiceFramework("IBcatService"), system{system_}, backend{backend_}, + progress{{ + ProgressServiceBackend{system_.Kernel(), "Normal"}, + ProgressServiceBackend{system_.Kernel(), "Directory"}, + }} { + // 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({system.CurrentProcess()->GetTitleID(), + GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + 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({system.CurrentProcess()->GetTitleID(), + GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + 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); + } + + Core::System& system; + Backend& backend; + + std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress; }; void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { @@ -37,20 +261,333 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IBcatService>(); + rb.PushIpcInterface<IBcatService>(system, *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(static_cast<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(static_cast<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(static_cast<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(system.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([[maybe_unused]] Core::System& system, + DirectoryGetter getter) { +#ifdef YUZU_ENABLE_BOXCAT + if (Settings::values.bcat_backend == "boxcat") { + return std::make_unique<Boxcat>(system.GetAppletManager(), 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(Core::System& system_, std::shared_ptr<Module> module_, + FileSystem::FileSystemController& fsc_, const char* name) + : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)}, + backend{CreateBackendFromSettings(system_, + [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })}, + system{system_} {} 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>(system, module, system.GetFileSystemController(), "bcat:a") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u") + ->InstallAsService(system.ServiceManager()); + std::make_shared<BCAT>(system, 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..e4ba23ba0 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h @@ -6,23 +6,46 @@ #include "core/hle/service/service.h" -namespace Service::BCAT { +namespace Core { +class System; +} + +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(Core::System& system_, 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; + + private: + Core::System& system; }; }; /// 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 afce581e5..4574d9572 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -34,8 +34,7 @@ public: RegisterHandlers(functions); auto& kernel = system.Kernel(); - register_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); + register_event = Kernel::WritableEvent::CreateEventPair(kernel, "BT:RegisterEvent"); } private: diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 920fc6ff7..251b3c9df 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -57,14 +57,12 @@ public: RegisterHandlers(functions); auto& kernel = system.Kernel(); - scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "IBtmUserCore:ScanEvent"); - connection_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ConnectionEvent"); - service_discovery = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IBtmUserCore:Discovery"); - config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "IBtmUserCore:ConfigEvent"); + scan_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ScanEvent"); + connection_event = + Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConnectionEvent"); + service_discovery = + Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:Discovery"); + config_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConfigEvent"); } private: diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index af70d174d..f77ddd739 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -128,7 +128,7 @@ private: void CountCommonTicket(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ETicket, "called"); - const auto count = keys.GetCommonTickets().size(); + const u32 count = static_cast<u32>(keys.GetCommonTickets().size()); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -138,7 +138,7 @@ private: void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ETicket, "called"); - const auto count = keys.GetPersonalizedTickets().size(); + const u32 count = static_cast<u32>(keys.GetPersonalizedTickets().size()); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -150,7 +150,7 @@ private: if (keys.GetCommonTickets().empty()) out_entries = 0; else - out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); @@ -160,7 +160,7 @@ private: std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), [](const auto& pair) { return pair.first; }); - out_entries = std::min<u32>(ids.size(), out_entries); + out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); IPC::ResponseBuilder rb{ctx, 3}; @@ -173,7 +173,7 @@ private: if (keys.GetPersonalizedTickets().empty()) out_entries = 0; else - out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); @@ -183,7 +183,7 @@ private: std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), [](const auto& pair) { return pair.first; }); - out_entries = std::min<u32>(ids.size(), out_entries); + out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index b2ebf6240..2546d7595 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -66,7 +66,7 @@ enum class FatalType : u32 { static void GenerateErrorReport(Core::System& system, ResultCode error_code, const FatalInfo& info) { - const auto title_id = Core::CurrentProcess()->GetTitleID(); + const auto title_id = system.CurrentProcess()->GetTitleID(); std::string crash_report = fmt::format( "Yuzu {}-{} crash report\n" "Title ID: {:016x}\n" diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 14cd0e322..102017d73 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -58,11 +58,11 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 auto file = dir->CreateFile(FileUtil::GetFilename(path)); if (file == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } if (!file->Resize(size)) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -80,7 +80,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons } if (!dir->DeleteFile(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -94,7 +94,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); if (new_dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -104,7 +104,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -114,7 +114,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -125,7 +125,7 @@ ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::stri if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -142,7 +142,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, return FileSys::ERROR_PATH_NOT_FOUND; if (!src->Rename(FileUtil::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -160,7 +160,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -177,7 +177,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa return FileSys::ERROR_PATH_NOT_FOUND; if (!src->Rename(FileUtil::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -189,7 +189,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa src_path, dest_path); // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_, @@ -241,7 +241,7 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( return FileSys::ERROR_PATH_NOT_FOUND; } -FileSystemController::FileSystemController() = default; +FileSystemController::FileSystemController(Core::System& system_) : system{system_} {} FileSystemController::~FileSystemController() = default; @@ -287,10 +287,10 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() if (romfs_factory == nullptr) { // TODO(bunnei): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } - return romfs_factory->OpenCurrentProcess(); + return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); } ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( @@ -300,7 +300,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( if (romfs_factory == nullptr) { // TODO(bunnei): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return romfs_factory->Open(title_id, storage_id, type); @@ -447,10 +447,10 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; FileSys::NACP nacp; - const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp); + const auto res = system.GetAppLoader().ReadControlData(nacp); if (res != Loader::ResultStatus::Success) { - FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()}; + FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; auto [nacp_unique, discard] = pm.GetControlMetadata(); if (nacp_unique != nullptr) { @@ -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; @@ -693,10 +702,10 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove if (bis_factory == nullptr) { bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory); - Core::System::GetInstance().RegisterContentProvider( - FileSys::ContentProviderUnionSlot::SysNAND, bis_factory->GetSystemNANDContents()); - Core::System::GetInstance().RegisterContentProvider( - FileSys::ContentProviderUnionSlot::UserNAND, bis_factory->GetUserNANDContents()); + system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SysNAND, + bis_factory->GetSystemNANDContents()); + system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::UserNAND, + bis_factory->GetUserNANDContents()); } if (save_data_factory == nullptr) { @@ -705,8 +714,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove if (sdmc_factory == nullptr) { sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); - Core::System::GetInstance().RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC, - sdmc_factory->GetSDMCContents()); + system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC, + sdmc_factory->GetSDMCContents()); } } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 3e0c03ec0..1b0a6a949 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -10,6 +10,10 @@ #include "core/file_sys/vfs.h" #include "core/hle/result.h" +namespace Core { +class System; +} + namespace FileSys { class BISFactory; class RegisteredCache; @@ -52,7 +56,7 @@ enum class ImageDirectoryId : u32 { class FileSystemController { public: - FileSystemController(); + explicit FileSystemController(Core::System& system_); ~FileSystemController(); ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); @@ -110,6 +114,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); @@ -123,6 +129,8 @@ private: std::unique_ptr<FileSys::XCI> gamecard; std::unique_ptr<FileSys::RegisteredCache> gamecard_registered; std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder; + + Core::System& system; }; void InstallInterfaces(Core::System& system); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index eb982ad49..92162d3e1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -785,7 +785,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { static_cast<u8>(type), title_id); IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); } void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { @@ -803,7 +803,7 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); - auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); + [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); u128 uid = rp.PopRaw<u128>(); LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), @@ -891,7 +891,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { // TODO (bunnei): Find the right error code to use here LOG_CRITICAL(Service_FS, "no file system interface available!"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -928,7 +928,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, static_cast<u8>(storage_id)); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 42b4ee861..1a0214f08 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -162,7 +162,7 @@ public: RegisterHandlers(functions); notification_event = Kernel::WritableEvent::CreateEventPair( - system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); + system.Kernel(), "INotificationService:NotifyEvent"); } private: @@ -237,7 +237,6 @@ private: }; Common::UUID uuid; - bool is_event_created = false; Kernel::EventPair notification_event; std::queue<SizedNotificationInfo> notifications; States states{}; diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 8e8263f5b..1f2131ec8 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -11,11 +11,10 @@ namespace Service::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; -constexpr s32 HID_JOYSTICK_MIN = -0x7fff; +[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; -Controller_DebugPad::Controller_DebugPad(Core::System& system) - : ControllerBase(system), system(system) {} +Controller_DebugPad::Controller_DebugPad(Core::System& system) : ControllerBase(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 6c4de817e..555b29d76 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -89,6 +89,5 @@ 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 80da0a0d3..6e990dd00 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -10,8 +10,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; -Controller_Gesture::Controller_Gesture(Core::System& system) - : ControllerBase(system), system(system) {} +Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(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 396897527..f650b8338 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -59,6 +59,5 @@ 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 e587b2e15..358cb9329 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,8 +12,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; constexpr u8 KEYS_PER_BYTE = 8; -Controller_Keyboard::Controller_Keyboard(Core::System& system) - : ControllerBase(system), system(system) {} +Controller_Keyboard::Controller_Keyboard(Core::System& system) : ControllerBase(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 ef586f7eb..f3eef5936 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -53,6 +53,5 @@ 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 88f2ca4c1..93d88ea50 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(Core::System& system) : ControllerBase(system), system(system) {} +Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(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 df2da6ae3..357ab7107 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -53,6 +53,5 @@ 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 44b668fbf..79fff517e 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -20,7 +20,7 @@ namespace Service::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; -constexpr s32 HID_JOYSTICK_MIN = -0x7fff; +[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; constexpr std::size_t NPAD_OFFSET = 0x9A00; constexpr u32 BATTERY_FULL = 2; constexpr u32 MAX_NPAD_ID = 7; @@ -105,6 +105,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { controller.joy_styles.raw = 0; // Zero out controller.device_type.raw = 0; switch (controller_type) { + case NPadControllerType::None: + UNREACHABLE(); case NPadControllerType::Handheld: controller.joy_styles.handheld.Assign(1); controller.device_type.handheld.Assign(1); @@ -165,13 +167,14 @@ 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 = system.Kernel(); for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, fmt::format("npad:NpadStyleSetChanged_{}", i)); + kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); } if (!IsControllerActivated()) { @@ -238,7 +241,7 @@ void Controller_NPad::OnRelease() {} void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { const auto controller_idx = NPadIdToIndex(npad_id); - const auto controller_type = connected_controllers[controller_idx].type; + [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type; if (!connected_controllers[controller_idx].is_connected) { return; } @@ -345,6 +348,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_entry.connection_status.raw = 0; switch (controller_type) { + case NPadControllerType::None: + UNREACHABLE(); case NPadControllerType::Handheld: handheld_entry.connection_status.raw = 0; handheld_entry.connection_status.IsWired.Assign(1); @@ -433,7 +438,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) { @@ -452,10 +456,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_events[i].writable->Signal(); } } } @@ -481,7 +481,6 @@ 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()); if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { - styleset_changed_events[npad_index].writable->Signal(); shared_memory_entries[npad_index].pad_assignment = assignment_mode; } } @@ -507,7 +506,6 @@ Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEven // 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? const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; - styleset_event.writable->Signal(); return styleset_event.readable; } @@ -585,36 +583,6 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { return true; } -bool Controller_NPad::IsControllerSupported(NPadControllerType controller) { - if (controller == NPadControllerType::Handheld) { - // Handheld is not even a supported type, lets stop here - if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), - NPAD_HANDHELD) == supported_npad_id_types.end()) { - return false; - } - // Handheld should not be supported in docked mode - if (Settings::values.use_docked_mode) { - return false; - } - } - switch (controller) { - case NPadControllerType::ProController: - return style.pro_controller; - case NPadControllerType::Handheld: - return style.handheld; - case NPadControllerType::JoyDual: - return style.joycon_dual; - case NPadControllerType::JoyLeft: - return style.joycon_left; - case NPadControllerType::JoyRight: - return style.joycon_right; - case NPadControllerType::Pokeball: - return style.pokeball; - default: - return false; - } -} - Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { // These are controllers without led patterns @@ -661,25 +629,24 @@ void Controller_NPad::ClearAllConnectedControllers() { } void Controller_NPad::DisconnectAllConnectedControllers() { - std::for_each(connected_controllers.begin(), connected_controllers.end(), - [](ControllerHolder& controller) { controller.is_connected = false; }); + for (ControllerHolder& controller : connected_controllers) { + controller.is_connected = false; + } } void Controller_NPad::ConnectAllDisconnectedControllers() { - std::for_each(connected_controllers.begin(), connected_controllers.end(), - [](ControllerHolder& controller) { - if (controller.type != NPadControllerType::None && !controller.is_connected) { - controller.is_connected = false; - } - }); + for (ControllerHolder& controller : connected_controllers) { + if (controller.type != NPadControllerType::None && !controller.is_connected) { + controller.is_connected = true; + } + } } void Controller_NPad::ClearAllControllers() { - std::for_each(connected_controllers.begin(), connected_controllers.end(), - [](ControllerHolder& controller) { - controller.type = NPadControllerType::None; - controller.is_connected = false; - }); + for (ControllerHolder& controller : connected_controllers) { + controller.type = NPadControllerType::None; + controller.is_connected = false; + } } u32 Controller_NPad::GetAndResetPressState() { @@ -687,10 +654,10 @@ u32 Controller_NPad::GetAndResetPressState() { } bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { - const bool support_handheld = - std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != - supported_npad_id_types.end(); if (controller == NPadControllerType::Handheld) { + const bool support_handheld = + std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), + NPAD_HANDHELD) != supported_npad_id_types.end(); // Handheld is not even a supported type, lets stop here if (!support_handheld) { return false; @@ -702,6 +669,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const return true; } + if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { switch (controller) { @@ -719,6 +687,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const return false; } } + return false; } @@ -797,6 +766,7 @@ Controller_NPad::NPadControllerType Controller_NPad::DecideBestController( priority_list.push_back(NPadControllerType::JoyLeft); priority_list.push_back(NPadControllerType::JoyRight); priority_list.push_back(NPadControllerType::JoyDual); + break; } const auto iter = std::find_if(priority_list.begin(), priority_list.end(), diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 1bc3d55d6..16c4caa1f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -301,6 +301,11 @@ private: bool is_connected; }; + void InitNewlyAddedControler(std::size_t controller_idx); + bool IsControllerSupported(NPadControllerType controller) const; + NPadControllerType DecideBestController(NPadControllerType priority) const; + void RequestPadStateUpdate(u32 npad_id); + u32 press_state{}; NPadType style{}; @@ -321,12 +326,7 @@ private: std::array<ControllerHolder, 10> connected_controllers{}; bool can_controllers_vibrate{true}; - void InitNewlyAddedControler(std::size_t controller_idx); - bool IsControllerSupported(NPadControllerType controller) const; - NPadControllerType DecideBestController(NPadControllerType priority) const; - void RequestPadStateUpdate(u32 npad_id); std::array<ControllerPad, 10> npad_pad_states{}; - bool IsControllerSupported(NPadControllerType controller); bool is_in_lr_assignment_mode{false}; Core::System& system; }; diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 9b829341e..9e527d176 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -9,8 +9,7 @@ namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::System& system) - : ControllerBase(system), system(system) {} +Controller_Stubbed::Controller_Stubbed(Core::System& system) : ControllerBase(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 37d7d8538..4fa83ac85 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -30,6 +30,5 @@ 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 25912fd69..1c6e55566 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -13,8 +13,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::System& system) - : ControllerBase(system), system(system) {} +Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(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 3429c84db..a1d97269e 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -69,6 +69,5 @@ 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 1bce044b4..27511b27b 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(Core::System& system) : ControllerBase(system), system(system) {} +Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(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 c445ebec0..ad229787c 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -56,6 +56,5 @@ 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 8d76ba746..ecc130f6c 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -38,8 +38,10 @@ namespace Service::HID { // Updating period for each HID device. // TODO(ogniK): Find actual polling rate of hid constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); -constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); -constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); +[[maybe_unused]] constexpr s64 accelerometer_update_ticks = + static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); +[[maybe_unused]] constexpr s64 gyroscope_update_ticks = + static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system) @@ -193,7 +195,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, {103, &Hid::ActivateNpad, "ActivateNpad"}, - {104, nullptr, "DeactivateNpad"}, + {104, &Hid::DeactivateNpad, "DeactivateNpad"}, {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, {107, &Hid::DisconnectNpad, "DisconnectNpad"}, {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, @@ -201,13 +203,13 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, - {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, + {123, &Hid::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"}, {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"}, {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"}, {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, - {129, nullptr, "GetNpadHandheldActivationMode"}, + {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"}, {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, @@ -468,6 +470,17 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { applet_resource->ActivateController(HidController::NPad); } +void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + applet_resource->DeactivateController(HidController::NPad); +} + void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto npad_id{rp.Pop<u32>()}; @@ -544,10 +557,126 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { + // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto npad_joy_device_type{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", + npad_id, applet_resource_user_id, npad_joy_device_type); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } +void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown_1{rp.Pop<u32>()}; + const auto unknown_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + unknown_1, unknown_2, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.StartLRAssignmentMode(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.StopLRAssignmentMode(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto mode{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", + applet_resource_user_id, mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_1{rp.Pop<u32>()}; + const auto npad_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", + applet_resource_user_id, npad_1, npad_2); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 2}; + if (controller.SwapNpadAssignment(npad_1, npad_2)) { + rb.Push(RESULT_SUCCESS); + } else { + LOG_ERROR(Service_HID, "Npads are not connected!"); + rb.Push(ERR_NPAD_NOT_CONNECTED); + } +} + void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; @@ -622,47 +751,6 @@ void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); } -void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, - applet_resource_user_id); - - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown_1{rp.Pop<u32>()}; - const auto unknown_2{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_WARNING(Service_HID, - "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", - unknown_1, unknown_2, applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto mode{rp.Pop<u64>()}; - - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", - applet_resource_user_id, mode); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called"); @@ -756,49 +844,6 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.StartLRAssignmentMode(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.StopLRAssignmentMode(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_1{rp.Pop<u32>()}; - const auto npad_2{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", - applet_resource_user_id, npad_1, npad_2); - - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 2}; - if (controller.SwapNpadAssignment(npad_1, npad_2)) { - rb.Push(RESULT_SUCCESS); - } else { - LOG_ERROR(Service_HID, "Npads are not connected!"); - rb.Push(ERR_NPAD_NOT_CONNECTED); - } -} - class HidDbg final : public ServiceFramework<HidDbg> { public: explicit HidDbg() : ServiceFramework{"hid:dbg"} { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 35b663679..f08e036a3 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -99,20 +99,26 @@ private: void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); void ActivateNpad(Kernel::HLERequestContext& ctx); + void DeactivateNpad(Kernel::HLERequestContext& ctx); void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); void DisconnectNpad(Kernel::HLERequestContext& ctx); void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); + void StartLrAssignmentMode(Kernel::HLERequestContext& ctx); + void StopLrAssignmentMode(Kernel::HLERequestContext& ctx); + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void SwapNpadAssignment(Kernel::HLERequestContext& ctx); void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); void SendVibrationValue(Kernel::HLERequestContext& ctx); void SendVibrationValues(Kernel::HLERequestContext& ctx); void GetActualVibrationValue(Kernel::HLERequestContext& ctx); - void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); - void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); - void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); void PermitVibration(Kernel::HLERequestContext& ctx); @@ -122,9 +128,6 @@ private: void StopSixAxisSensor(Kernel::HLERequestContext& ctx); void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); - void StartLrAssignmentMode(Kernel::HLERequestContext& ctx); - void StopLrAssignmentMode(Kernel::HLERequestContext& ctx); - void SwapNpadAssignment(Kernel::HLERequestContext& ctx); std::shared_ptr<IAppletResource> applet_resource; Core::System& system; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 3164ca26e..88f903bfd 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -163,7 +163,7 @@ public: return; } - if (Core::CurrentProcess()->GetTitleID() != header.title_id) { + if (system.CurrentProcess()->GetTitleID() != header.title_id) { LOG_ERROR(Service_LDR, "Attempting to load NRR with title ID other than current process. (actual " "{:016X})!", @@ -294,7 +294,7 @@ public: Memory::ReadBlock(nro_address, nro_data.data(), nro_size); SHA256Hash hash{}; - mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0); + mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0); // NRO Hash is already loaded if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) { @@ -327,7 +327,7 @@ public: } // Load NRO as new executable module - auto* process = Core::CurrentProcess(); + auto* process = system.CurrentProcess(); auto& vm_manager = process->VMManager(); auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size); @@ -411,7 +411,7 @@ public: return; } - auto& vm_manager = Core::CurrentProcess()->VMManager(); + auto& vm_manager = system.CurrentProcess()->VMManager(); const auto& nro_info = iter->second; // Unmap the mirrored memory diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 2a61593e2..435f2d286 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -6,8 +6,10 @@ #include <string> #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/lm/lm.h" +#include "core/hle/service/lm/manager.h" #include "core/hle/service/service.h" #include "core/memory.h" @@ -15,65 +17,16 @@ namespace Service::LM { class ILogger final : public ServiceFramework<ILogger> { public: - ILogger() : ServiceFramework("ILogger") { + ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) { static const FunctionInfo functions[] = { - {0x00000000, &ILogger::Initialize, "Initialize"}, - {0x00000001, &ILogger::SetDestination, "SetDestination"}, + {0, &ILogger::Log, "Log"}, + {1, &ILogger::SetDestination, "SetDestination"}, }; RegisterHandlers(functions); } private: - struct MessageHeader { - enum Flags : u32_le { - IsHead = 1, - IsTail = 2, - }; - enum Severity : u32_le { - Trace, - Info, - Warning, - Error, - Critical, - }; - - u64_le pid; - u64_le threadContext; - union { - BitField<0, 16, Flags> flags; - BitField<16, 8, Severity> severity; - BitField<24, 8, u32> verbosity; - }; - u32_le payload_size; - - bool IsHeadLog() const { - return flags & Flags::IsHead; - } - bool IsTailLog() const { - return flags & Flags::IsTail; - } - }; - static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); - - /// Log field type - enum class Field : u8 { - Skip = 1, - Message = 2, - Line = 3, - Filename = 4, - Function = 5, - Module = 6, - Thread = 7, - }; - - /** - * ILogger::Initialize service function - * Inputs: - * 0: 0x00000000 - * Outputs: - * 0: ResultCode - */ - void Initialize(Kernel::HLERequestContext& ctx) { + void Log(Kernel::HLERequestContext& ctx) { // This function only succeeds - Get that out of the way IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -85,140 +38,70 @@ private: Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); addr += sizeof(MessageHeader); - if (header.IsHeadLog()) { - log_stream.str(""); - log_stream.clear(); - } - - // Parse out log metadata - u32 line{}; - std::string module; - std::string message; - std::string filename; - std::string function; - std::string thread; + FieldMap fields; while (addr < end_addr) { - const Field field{static_cast<Field>(Memory::Read8(addr++))}; - const std::size_t length{Memory::Read8(addr++)}; + const auto field = static_cast<Field>(Memory::Read8(addr++)); + const auto length = Memory::Read8(addr++); if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { ++addr; } - switch (field) { - case Field::Skip: - break; - case Field::Message: - message = Memory::ReadCString(addr, length); - break; - case Field::Line: - line = Memory::Read32(addr); - break; - case Field::Filename: - filename = Memory::ReadCString(addr, length); - break; - case Field::Function: - function = Memory::ReadCString(addr, length); - break; - case Field::Module: - module = Memory::ReadCString(addr, length); - break; - case Field::Thread: - thread = Memory::ReadCString(addr, length); - break; - } + SCOPE_EXIT({ addr += length; }); - addr += length; - } + if (field == Field::Skip) { + continue; + } - // Empty log - nothing to do here - if (log_stream.str().empty() && message.empty()) { - return; + std::vector<u8> data(length); + Memory::ReadBlock(addr, data.data(), length); + fields.emplace(field, std::move(data)); } - // Format a nicely printable string out of the log metadata - if (!filename.empty()) { - log_stream << filename << ':'; - } - if (!module.empty()) { - log_stream << module << ':'; - } - if (!function.empty()) { - log_stream << function << ':'; - } - if (line) { - log_stream << std::to_string(line) << ':'; - } - if (!thread.empty()) { - log_stream << thread << ':'; - } - if (log_stream.str().length() > 0 && log_stream.str().back() == ':') { - log_stream << ' '; - } - log_stream << message; - - if (header.IsTailLog()) { - switch (header.severity) { - case MessageHeader::Severity::Trace: - LOG_DEBUG(Debug_Emulated, "{}", log_stream.str()); - break; - case MessageHeader::Severity::Info: - LOG_INFO(Debug_Emulated, "{}", log_stream.str()); - break; - case MessageHeader::Severity::Warning: - LOG_WARNING(Debug_Emulated, "{}", log_stream.str()); - break; - case MessageHeader::Severity::Error: - LOG_ERROR(Debug_Emulated, "{}", log_stream.str()); - break; - case MessageHeader::Severity::Critical: - LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); - break; - } - } + manager.Log({header, std::move(fields)}); } - // This service function is intended to be used as a way to - // redirect logging output to different destinations, however, - // given we always want to see the logging output, it's sufficient - // to do nothing and return success here. void SetDestination(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_LM, "called"); + IPC::RequestParser rp{ctx}; + const auto destination = rp.PopEnum<DestinationFlag>(); + + LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination)); + + manager.SetDestination(destination); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - std::ostringstream log_stream; + Manager& manager; }; class LM final : public ServiceFramework<LM> { public: - explicit LM() : ServiceFramework{"lm"} { + explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) { + // clang-format off static const FunctionInfo functions[] = { - {0x00000000, &LM::OpenLogger, "OpenLogger"}, + {0, &LM::OpenLogger, "OpenLogger"}, }; + // clang-format on + RegisterHandlers(functions); } - /** - * LM::OpenLogger service function - * Inputs: - * 0: 0x00000000 - * Outputs: - * 0: ResultCode - */ +private: void OpenLogger(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_LM, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILogger>(); + rb.PushIpcInterface<ILogger>(manager); } + + Manager& manager; }; -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<LM>()->InstallAsService(service_manager); +void InstallInterfaces(Core::System& system) { + std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager()); } } // namespace Service::LM diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h index 7806ae27b..d40410b5c 100644 --- a/src/core/hle/service/lm/lm.h +++ b/src/core/hle/service/lm/lm.h @@ -4,13 +4,13 @@ #pragma once -namespace Service::SM { -class ServiceManager; +namespace Core { +class System; } namespace Service::LM { /// Registers all LM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(Core::System& system); } // namespace Service::LM diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp new file mode 100644 index 000000000..b67081b86 --- /dev/null +++ b/src/core/hle/service/lm/manager.cpp @@ -0,0 +1,133 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/hle/service/lm/manager.h" +#include "core/reporter.h" + +namespace Service::LM { + +std::ostream& operator<<(std::ostream& os, DestinationFlag dest) { + std::vector<std::string> array; + const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) { + if ((static_cast<u32>(check) & static_cast<u32>(dest)) != 0) { + array.emplace_back(std::move(name)); + } + }; + + check_single_flag(DestinationFlag::Default, "Default"); + check_single_flag(DestinationFlag::UART, "UART"); + check_single_flag(DestinationFlag::UARTSleeping, "UART (Sleeping)"); + + os << "["; + for (const auto& entry : array) { + os << entry << ", "; + } + return os << "]"; +} + +std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity) { + switch (severity) { + case MessageHeader::Severity::Trace: + return os << "Trace"; + case MessageHeader::Severity::Info: + return os << "Info"; + case MessageHeader::Severity::Warning: + return os << "Warning"; + case MessageHeader::Severity::Error: + return os << "Error"; + case MessageHeader::Severity::Critical: + return os << "Critical"; + default: + return os << fmt::format("{:08X}", static_cast<u32>(severity)); + } +} + +std::ostream& operator<<(std::ostream& os, Field field) { + switch (field) { + case Field::Skip: + return os << "Skip"; + case Field::Message: + return os << "Message"; + case Field::Line: + return os << "Line"; + case Field::Filename: + return os << "Filename"; + case Field::Function: + return os << "Function"; + case Field::Module: + return os << "Module"; + case Field::Thread: + return os << "Thread"; + default: + return os << fmt::format("{:08X}", static_cast<u32>(field)); + } +} + +std::string FormatField(Field type, const std::vector<u8>& data) { + switch (type) { + case Field::Skip: + return ""; + case Field::Line: + if (data.size() >= sizeof(u32)) { + u32 line; + std::memcpy(&line, data.data(), sizeof(u32)); + return fmt::format("{}", line); + } + return "[ERROR DECODING LINE NUMBER]"; + case Field::Message: + case Field::Filename: + case Field::Function: + case Field::Module: + case Field::Thread: + return Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast<const char*>(data.data()), data.size()); + default: + UNIMPLEMENTED(); + } +} + +Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {} + +Manager::~Manager() = default; + +void Manager::SetEnabled(bool enabled) { + this->enabled = enabled; +} + +void Manager::SetDestination(DestinationFlag destination) { + this->destination = destination; +} + +void Manager::Log(LogMessage message) { + if (message.header.IsHeadLog()) { + InitializeLog(); + } + + current_log.emplace_back(std::move(message)); + + if (current_log.back().header.IsTailLog()) { + FinalizeLog(); + } +} + +void Manager::Flush() { + FinalizeLog(); +} + +void Manager::InitializeLog() { + current_log.clear(); + + LOG_INFO(Service_LM, "Initialized new log session"); +} + +void Manager::FinalizeLog() { + reporter.SaveLogReport(static_cast<u32>(destination), std::move(current_log)); + + LOG_INFO(Service_LM, "Finalized current log session"); +} + +} // namespace Service::LM diff --git a/src/core/hle/service/lm/manager.h b/src/core/hle/service/lm/manager.h new file mode 100644 index 000000000..544e636ba --- /dev/null +++ b/src/core/hle/service/lm/manager.h @@ -0,0 +1,106 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <ostream> +#include <vector> +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Core { +class Reporter; +} + +namespace Service::LM { + +enum class DestinationFlag : u32 { + Default = 1, + UART = 2, + UARTSleeping = 4, + + All = 0xFFFF, +}; + +struct MessageHeader { + enum Flags : u32_le { + IsHead = 1, + IsTail = 2, + }; + enum Severity : u32_le { + Trace, + Info, + Warning, + Error, + Critical, + }; + + u64_le pid; + u64_le thread_context; + union { + BitField<0, 16, Flags> flags; + BitField<16, 8, Severity> severity; + BitField<24, 8, u32> verbosity; + }; + u32_le payload_size; + + bool IsHeadLog() const { + return flags & IsHead; + } + bool IsTailLog() const { + return flags & IsTail; + } +}; +static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); + +enum class Field : u8 { + Skip = 1, + Message = 2, + Line = 3, + Filename = 4, + Function = 5, + Module = 6, + Thread = 7, +}; + +std::ostream& operator<<(std::ostream& os, DestinationFlag dest); +std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity); +std::ostream& operator<<(std::ostream& os, Field field); + +using FieldMap = std::map<Field, std::vector<u8>>; + +struct LogMessage { + MessageHeader header; + FieldMap fields; +}; + +std::string FormatField(Field type, const std::vector<u8>& data); + +class Manager { +public: + explicit Manager(Core::Reporter& reporter); + ~Manager(); + + void SetEnabled(bool enabled); + void SetDestination(DestinationFlag destination); + + void Log(LogMessage message); + + void Flush(); + +private: + void InitializeLog(); + void FinalizeLog(); + + bool enabled = true; + DestinationFlag destination = DestinationFlag::All; + + std::vector<LogMessage> current_log; + + Core::Reporter& reporter; +}; + +} // namespace Service::LM diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index 0b3923ad9..0ffc5009e 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -242,7 +242,7 @@ private: const auto index = db.IndexOf(uuid); if (index > MAX_MIIS) { // TODO(DarkLordZach): Find a better error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); rb.Push(index); } else { rb.Push(RESULT_SUCCESS); @@ -268,7 +268,7 @@ private: IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : ResultCode(-1)); + rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); } void AddOrReplace(Kernel::HLERequestContext& ctx) { @@ -282,7 +282,7 @@ private: IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : ResultCode(-1)); + rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); } void Delete(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a42c22d44..3bf753dee 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -16,18 +16,14 @@ #include "core/hle/service/nfp/nfp_user.h" namespace Service::NFP { - namespace ErrCodes { -constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, - -1); // TODO(ogniK): Find the actual error code constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); } // namespace ErrCodes 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"); + nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected"); } Module::Interface::~Interface() = default; @@ -35,7 +31,7 @@ Module::Interface::~Interface() = default; class IUser final : public ServiceFramework<IUser> { public: IUser(Module::Interface& nfp_interface, Core::System& system) - : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) { + : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { static const FunctionInfo functions[] = { {0, &IUser::Initialize, "Initialize"}, {1, &IUser::Finalize, "Finalize"}, @@ -66,10 +62,9 @@ public: RegisterHandlers(functions); auto& kernel = system.Kernel(); - deactivate_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); - availability_change_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, "IUser:AvailabilityChangeEvent"); + deactivate_event = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:DeactivateEvent"); + availability_change_event = + Kernel::WritableEvent::CreateEventPair(kernel, "IUser:AvailabilityChangeEvent"); } private: @@ -183,6 +178,8 @@ private: case DeviceState::TagRemoved: device_state = DeviceState::Initialized; break; + default: + break; } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -324,7 +321,6 @@ 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) { diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 24d1813a7..01d557c7a 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") { @@ -62,10 +69,8 @@ public: RegisterHandlers(functions); auto& kernel = system.Kernel(); - event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "IRequest:Event1"); - event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "IRequest:Event2"); + event1 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event1"); + event2 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event2"); } private: @@ -81,7 +86,7 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0); + rb.PushEnum(RequestState::Connected); } void GetResult(Kernel::HLERequestContext& ctx) { @@ -189,14 +194,14 @@ 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; }; diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 75d414952..7d6cf2070 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -141,8 +141,7 @@ public: auto& kernel = system.Kernel(); finished_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, - "IEnsureNetworkClockAvailabilityService:FinishEvent"); + kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent"); } private: diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 15c156ce1..eeba0aa19 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -271,7 +271,7 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size); IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -291,7 +291,7 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC 0x4000 + control.second->GetSize()); IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 7dcdb4a07..db433305f 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -6,13 +6,6 @@ #include <cstring> #include <vector> -#include <FontChineseSimplified.h> -#include <FontChineseTraditional.h> -#include <FontExtendedChineseSimplified.h> -#include <FontKorean.h> -#include <FontNintendoExtended.h> -#include <FontStandard.h> - #include "common/assert.h" #include "common/common_paths.h" #include "common/common_types.h" @@ -24,7 +17,9 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/physical_memory.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/pl_u.h" @@ -94,15 +89,20 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem offset += transformed_font.size() * sizeof(u32); } -static void EncryptSharedFont(const std::vector<u8>& input, Kernel::PhysicalMemory& output, - std::size_t& offset) { - ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); - const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT; - std::memcpy(output.data() + offset, &EXPECTED_RESULT, sizeof(u32)); // Magic header - const u32 ENC_SIZE = static_cast<u32>(input.size()) ^ KEY; - std::memcpy(output.data() + offset + sizeof(u32), &ENC_SIZE, sizeof(u32)); - std::memcpy(output.data() + offset + (sizeof(u32) * 2), input.data(), input.size()); - offset += input.size() + (sizeof(u32) * 2); +void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, + std::size_t& offset) { + ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, + "Shared fonts exceeds 17mb!"); + + const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC); + std::vector<u32> transformed_font(input.size() + 2); + transformed_font[0] = Common::swap32(EXPECTED_MAGIC); + transformed_font[1] = Common::swap32(static_cast<u32>(input.size() * sizeof(u32))) ^ key; + std::transform(input.begin(), input.end(), transformed_font.begin() + 2, + [key](u32 in) { return in ^ key; }); + std::memcpy(output.data() + offset, transformed_font.data(), + transformed_font.size() * sizeof(u32)); + offset += transformed_font.size() * sizeof(u32); } // Helper function to make BuildSharedFontsRawRegions a bit nicer @@ -168,114 +168,49 @@ PL_U::PL_U(Core::System& system) // Attempt to load shared font data from disk const auto* nand = fsc.GetSystemNANDContents(); std::size_t offset = 0; - // Rebuild shared fonts from data ncas - if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), - FileSys::ContentRecordType::Data)) { - impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(SHARED_FONT_MEM_SIZE); - for (auto font : SHARED_FONTS) { - const auto nca = - nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); - if (!nca) { - LOG_ERROR(Service_NS, "Failed to find {:016X}! Skipping", - static_cast<u64>(font.first)); - continue; - } - const auto romfs = nca->GetRomFS(); - if (!romfs) { - LOG_ERROR(Service_NS, "{:016X} has no RomFS! Skipping", - static_cast<u64>(font.first)); - continue; - } - const auto extracted_romfs = FileSys::ExtractRomFS(romfs); - if (!extracted_romfs) { - LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", - static_cast<u64>(font.first)); - continue; - } - const auto font_fp = extracted_romfs->GetFile(font.second); - if (!font_fp) { - LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", - static_cast<u64>(font.first), font.second); - continue; - } - std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32)); - font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize()); - // We need to be BigEndian as u32s for the xor encryption - std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), - Common::swap32); - FontRegion region{ - static_cast<u32>(offset + 8), - static_cast<u32>((font_data_u32.size() * sizeof(u32)) - - 8)}; // Font offset and size do not account for the header - DecryptSharedFont(font_data_u32, *impl->shared_font, offset); - impl->shared_font_regions.push_back(region); + // Rebuild shared fonts from data ncas or synthesize + + impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(SHARED_FONT_MEM_SIZE); + for (auto font : SHARED_FONTS) { + FileSys::VirtualFile romfs; + const auto nca = + nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); + if (nca) { + romfs = nca->GetRomFS(); } - } else { - impl->shared_font = std::make_shared<Kernel::PhysicalMemory>( - SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size - - const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); - const std::string filepath{user_path + SHARED_FONT}; + if (!romfs) { + romfs = FileSys::SystemArchive::SynthesizeSystemArchive(static_cast<u64>(font.first)); + } - // Create path if not already created - if (!FileUtil::CreateFullPath(filepath)) { - LOG_ERROR(Service_NS, "Failed to create sharedfonts path \"{}\"!", filepath); - return; + if (!romfs) { + LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", + static_cast<u64>(font.first)); + continue; } - bool using_ttf = false; - for (const char* font_ttf : SHARED_FONTS_TTF) { - if (FileUtil::Exists(user_path + font_ttf)) { - using_ttf = true; - FileUtil::IOFile file(user_path + font_ttf, "rb"); - if (file.IsOpen()) { - std::vector<u8> ttf_bytes(file.GetSize()); - file.ReadBytes<u8>(ttf_bytes.data(), ttf_bytes.size()); - FontRegion region{ - static_cast<u32>(offset + 8), - static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account - // for the header - EncryptSharedFont(ttf_bytes, *impl->shared_font, offset); - impl->shared_font_regions.push_back(region); - } else { - LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf); - } - } else if (using_ttf) { - LOG_WARNING(Service_NS, "Unable to find font: {}", font_ttf); - } + const auto extracted_romfs = FileSys::ExtractRomFS(romfs); + if (!extracted_romfs) { + LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", + static_cast<u64>(font.first)); + continue; } - if (using_ttf) - return; - FileUtil::IOFile file(filepath, "rb"); - - if (file.IsOpen()) { - // Read shared font data - ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); - file.ReadBytes(impl->shared_font->data(), impl->shared_font->size()); - impl->BuildSharedFontsRawRegions(*impl->shared_font); - } else { - LOG_WARNING(Service_NS, - "Shared Font file missing. Loading open source replacement from memory"); - - // clang-format off - const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = { - {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)}, - {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)}, - {std::begin(FontExtendedChineseSimplified), std::end(FontExtendedChineseSimplified)}, - {std::begin(FontKorean), std::end(FontKorean)}, - {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)}, - {std::begin(FontStandard), std::end(FontStandard)}, - }; - // clang-format on - - for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) { - const FontRegion region{static_cast<u32>(offset + 8), - static_cast<u32>(font_ttf.size())}; - EncryptSharedFont(font_ttf, *impl->shared_font, offset); - impl->shared_font_regions.push_back(region); - } + const auto font_fp = extracted_romfs->GetFile(font.second); + if (!font_fp) { + LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", + static_cast<u64>(font.first), font.second); + continue; } + std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32)); + font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize()); + // We need to be BigEndian as u32s for the xor encryption + std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), + Common::swap32); + // Font offset and size do not account for the header + const FontRegion region{static_cast<u32>(offset + 8), + static_cast<u32>((font_data_u32.size() * sizeof(u32)) - 8)}; + DecryptSharedFont(font_data_u32, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); } } @@ -324,14 +259,14 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { // Map backing memory for the font data LOG_DEBUG(Service_NS, "called"); - Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, - SHARED_FONT_MEM_SIZE, - Kernel::MemoryState::Shared); + system.CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, + SHARED_FONT_MEM_SIZE, + Kernel::MemoryState::Shared); // Create shared font memory object auto& kernel = system.Kernel(); impl->shared_font_mem = Kernel::SharedMemory::Create( - kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, + kernel, system.CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, "PL_U:shared_font_mem"); diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 1063f4204..27161bd7a 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -5,6 +5,7 @@ #pragma once #include <memory> +#include <vector> #include "core/hle/service/service.h" namespace Service { @@ -15,6 +16,8 @@ class FileSystemController; namespace NS { +void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); + class PL_U final : public ServiceFramework<PL_U> { public: explicit PL_U(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 f764388bc..3f7b8e670 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/perf_stats.h" @@ -38,7 +39,10 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 transform, crop_rect}; system.GetPerfStats().EndGameFrame(); + system.GetPerfStats().EndSystemFrame(); system.GPU().SwapBuffers(&framebuffer); + system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); + system.GetPerfStats().BeginSystemFrame(); } } // namespace Service::Nvidia::Devices 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 6bc053f27..07c88465e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -45,6 +45,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std: return GetVARegions(input, output); case IoctlCommand::IocUnmapBufferCommand: return UnmapBuffer(input, output); + default: + break; } if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index ff6b1abae..b27ee0502 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -38,9 +38,10 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::v return IocCtrlEventUnregister(input, output); case IoctlCommand::IocCtrlEventSignalCommand: return IocCtrlEventSignal(input, output); + default: + UNIMPLEMENTED_MSG("Unimplemented ioctl"); + return 0; } - UNIMPLEMENTED_MSG("Unimplemented ioctl"); - return 0; } u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { @@ -62,16 +63,26 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& return NvResult::BadParameter; } + u32 event_id = params.value & 0x00FF; + + if (event_id >= MaxNvEvents) { + std::memcpy(output.data(), ¶ms, sizeof(params)); + return NvResult::BadParameter; + } + + auto event = events_interface.events[event_id]; auto& gpu = system.GPU(); // This is mostly to take into account unimplemented features. As synced // gpu is always synced. if (!gpu.IsAsync()) { + event.writable->Signal(); return NvResult::Success; } auto lock = gpu.LockSync(); const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); const s32 diff = current_syncpoint_value - params.threshold; if (diff >= 0) { + event.writable->Signal(); params.value = current_syncpoint_value; std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; @@ -87,27 +98,6 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& return NvResult::Timeout; } - u32 event_id; - if (is_async) { - event_id = params.value & 0x00FF; - if (event_id >= MaxNvEvents) { - std::memcpy(output.data(), ¶ms, sizeof(params)); - return NvResult::BadParameter; - } - } else { - if (ctrl.fresh_call) { - const auto result = events_interface.GetFreeEvent(); - if (result) { - event_id = *result; - } else { - LOG_CRITICAL(Service_NVDRV, "No Free Events available!"); - event_id = params.value & 0x00FF; - } - } else { - event_id = ctrl.event_id; - } - } - EventState status = events_interface.status[event_id]; if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) { events_interface.SetEventStatus(event_id, EventState::Waiting); @@ -119,7 +109,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; } params.value |= event_id; - events_interface.events[event_id].writable->Clear(); + event.writable->Clear(); gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); if (!is_async && ctrl.fresh_call) { ctrl.must_delay = true; 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 389ace76f..cc2192e5c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -40,9 +40,10 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, return FlushL2(input, output); case IoctlCommand::IocGetGpuTime: return GetGpuTime(input, output); + default: + UNIMPLEMENTED_MSG("Unimplemented ioctl"); + return 0; } - UNIMPLEMENTED_MSG("Unimplemented ioctl"); - return 0; } u32 nvhost_ctrl_gpu::GetCharacteristics(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 2b8d1bef6..9de0ace22 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -44,6 +44,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve return GetWaitbase(input, output); case IoctlCommand::IocChannelSetTimeoutCommand: return ChannelSetTimeout(input, output); + default: + break; } if (command.group == NVGPU_IOCTL_MAGIC) { diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 5e0c23602..68d139cfb 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -134,7 +134,9 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(RESULT_SUCCESS); if (event_id < MaxNvEvents) { - rb.PushCopyObjects(nvdrv->GetEvent(event_id)); + auto event = nvdrv->GetEvent(event_id); + event->Clear(); + rb.PushCopyObjects(event); rb.Push<u32>(NvResult::Success); } else { rb.Push<u32>(0); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 307a7e928..cc9cd3fd1 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -40,8 +40,7 @@ Module::Module(Core::System& system) { auto& kernel = system.Kernel(); for (u32 i = 0; i < MaxNvEvents; i++) { std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); - events_interface.events[i] = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Automatic, event_label); + events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label); events_interface.status[i] = EventState::Free; events_interface.registered[i] = false; } diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index e1a07d3ee..1af11e80c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -14,10 +14,9 @@ namespace Service::NVFlinger { -BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { - auto& kernel = Core::System::GetInstance().Kernel(); - buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, - "BufferQueue NativeHandle"); +BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) + : id(id), layer_id(layer_id) { + buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, "BufferQueue NativeHandle"); } BufferQueue::~BufferQueue() = default; diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 356bedb81..8f9b18547 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -15,6 +15,10 @@ #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdata.h" +namespace Kernel { +class KernelCore; +} + namespace Service::NVFlinger { struct IGBPBuffer { @@ -44,7 +48,7 @@ public: NativeWindowFormat = 2, }; - BufferQueue(u32 id, u64 layer_id); + explicit BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id); ~BufferQueue(); enum class BufferTransformFlags : u32 { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2e4d707b9..cc9522aad 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -83,7 +83,7 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { const u64 layer_id = next_layer_id++; const u32 buffer_queue_id = next_buffer_queue_id++; - buffer_queues.emplace_back(buffer_queue_id, layer_id); + buffer_queues.emplace_back(system.Kernel(), buffer_queue_id, layer_id); display->CreateLayer(layer_id, buffer_queues.back()); return layer_id; } @@ -187,14 +187,18 @@ void NVFlinger::Compose() { MicroProfileFlip(); if (!buffer) { - // There was no queued buffer to draw, render previous frame - system.GetPerfStats().EndGameFrame(); - system.GPU().SwapBuffers({}); continue; } const auto& igbp_buffer = buffer->get().igbp_buffer; + const auto& gpu = system.GPU(); + const auto& multi_fence = buffer->get().multi_fence; + for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { + const auto& fence = multi_fence.fences[fence_id]; + gpu.WaitFence(fence.id, fence.value); + } + // Now send the buffer to the GPU for drawing. // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 831a427de..7c5302017 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -208,7 +208,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { AOC::InstallInterfaces(*sm, system); APM::InstallInterfaces(system); Audio::InstallInterfaces(*sm, system); - BCAT::InstallInterfaces(*sm); + BCAT::InstallInterfaces(system); BPC::InstallInterfaces(*sm); BtDrv::InstallInterfaces(*sm, system); BTM::InstallInterfaces(*sm, system); @@ -226,7 +226,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { LBL::InstallInterfaces(*sm); LDN::InstallInterfaces(*sm); LDR::InstallInterfaces(*sm, system); - LM::InstallInterfaces(*sm); + LM::InstallInterfaces(system); Migration::InstallInterfaces(*sm); Mii::InstallInterfaces(*sm); MM::InstallInterfaces(*sm); diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 1b9ab8401..62efe021e 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -34,12 +34,12 @@ static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, additional_info = {}; return; } - calendar_time.year = tm->tm_year + 1900; - calendar_time.month = tm->tm_mon + 1; - calendar_time.day = tm->tm_mday; - calendar_time.hour = tm->tm_hour; - calendar_time.minute = tm->tm_min; - calendar_time.second = tm->tm_sec; + calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); + calendar_time.month = static_cast<u8>(tm->tm_mon + 1); + calendar_time.day = static_cast<u8>(tm->tm_mday); + calendar_time.hour = static_cast<u8>(tm->tm_hour); + calendar_time.minute = static_cast<u8>(tm->tm_min); + calendar_time.second = static_cast<u8>(tm->tm_sec); additional_info.day_of_week = tm->tm_wday; additional_info.day_of_year = tm->tm_yday; @@ -322,7 +322,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { if (tm == nullptr) { LOG_ERROR(Service_Time, "tm is a nullptr"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find appropriate error code return; } @@ -331,12 +331,12 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; CalendarTime calendar_time{}; - calendar_time.year = tm->tm_year + 1900; - calendar_time.month = tm->tm_mon + 1; - calendar_time.day = tm->tm_mday; - calendar_time.hour = tm->tm_hour; - calendar_time.minute = tm->tm_min; - calendar_time.second = tm->tm_sec; + calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); + calendar_time.month = static_cast<u8>(tm->tm_mon + 1); + calendar_time.day = static_cast<u8>(tm->tm_mday); + calendar_time.hour = static_cast<u8>(tm->tm_hour); + calendar_time.minute = static_cast<u8>(tm->tm_min); + calendar_time.second = static_cast<u8>(tm->tm_sec); ClockSnapshot clock_snapshot{}; clock_snapshot.system_posix_time = time_since_epoch; diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 006a6d9ff..07033fb98 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -17,8 +17,8 @@ namespace Service::VI { 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)); + vsync_event = + Kernel::WritableEvent::CreateEventPair(kernel, fmt::format("Display VSync Event {}", id)); } Display::~Display() = default; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 199b30635..abfc3a801 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -45,7 +45,7 @@ struct DisplayInfo { /// Whether or not the display has a limited number of layers. u8 has_limited_layers{1}; - INSERT_PADDING_BYTES(7){}; + INSERT_PADDING_BYTES(7); /// Indicates the total amount of layers supported by the display. /// @note This is only valid if has_limited_layers is set. @@ -541,7 +541,7 @@ private: } else { // Wait the current thread until a buffer becomes available ctx.SleepClientThread( - "IHOSBinderDriver::DequeueBuffer", -1, + "IHOSBinderDriver::DequeueBuffer", UINT64_MAX, [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available |
