diff options
45 files changed, 701 insertions, 334 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0e49c03..ce46a2c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,17 @@ message(STATUS "Target architecture: ${ARCHITECTURE}") # Configure C++ standard # =========================== -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) +# boost asio's concept usage doesn't play nicely with some compilers yet. +add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) +if (MSVC) + add_compile_options(/std:c++latest) + + # cubeb and boost still make use of deprecated result_of. + add_definitions(-D_HAS_DEPRECATED_RESULT_OF) +else() + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() # Output binaries to bin/ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) @@ -330,14 +339,16 @@ elseif(SDL2_FOUND) endif() # Ensure libusb is properly configured (based on dolphin libusb include) -include(FindPkgConfig) -find_package(LibUSB) +if(NOT APPLE) + include(FindPkgConfig) + find_package(LibUSB) +endif() if (NOT LIBUSB_FOUND) add_subdirectory(externals/libusb) + set(LIBUSB_INCLUDE_DIR "") set(LIBUSB_LIBRARIES usb) endif() - # Prefer the -pthread flag on Linux. set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -2,7 +2,7 @@ yuzu emulator ============= [![Travis CI Build Status](https://travis-ci.com/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.com/yuzu-emu/yuzu) [![Azure Mainline CI Build Status](https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master)](https://dev.azure.com/yuzu-emu/yuzu/) -[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.gg/XQV6dn9) +[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.com/invite/u77vRWY) yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). @@ -16,7 +16,7 @@ yuzu is licensed under the GPLv2 (or any later version). Refer to the license.tx Check out our [website](https://yuzu-emu.org/)! -For development discussion, please join us on [Discord](https://discord.gg/XQV6dn9). +For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY). ### Development diff --git a/src/common/alignment.h b/src/common/alignment.h index f8c49e079..b37044bb6 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -11,7 +11,9 @@ namespace Common { template <typename T> constexpr T AlignUp(T value, std::size_t size) { static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); - return static_cast<T>(value + (size - value % size) % size); + auto mod{static_cast<T>(value % size)}; + value -= mod; + return static_cast<T>(mod == T{0} ? value : value + size); } template <typename T> diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 8997c7082..f87fe0abc 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -695,8 +695,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, } void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { - if (s128_keys.find({id, field1, field2}) != s128_keys.end()) + if (s128_keys.find({id, field1, field2}) != s128_keys.end() || key == Key128{}) { return; + } if (id == S128KeyType::Titlekey) { Key128 rights_id; std::memcpy(rights_id.data(), &field2, sizeof(u64)); @@ -716,8 +717,9 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == std::tie(id, field1, field2); }); - if (iter2 != s128_file_id.end()) + if (iter2 != s128_file_id.end()) { WriteKeyToFile(category, iter2->first, key); + } // Variable cases if (id == S128KeyType::KeyArea) { @@ -745,16 +747,18 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { } void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { - if (s256_keys.find({id, field1, field2}) != s256_keys.end()) + if (s256_keys.find({id, field1, field2}) != s256_keys.end() || key == Key256{}) { return; + } const auto iter = std::find_if( s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == std::tie(id, field1, field2); }); - if (iter != s256_file_id.end()) + if (iter != s256_file_id.end()) { WriteKeyToFile(KeyCategory::Standard, iter->first, key); + } s256_keys[{id, field1, field2}] = key; } diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index e21300a7c..96ce5957c 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -112,19 +112,26 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ const auto new_path = FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); - if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || - FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) - return nullptr; - if (cache.find(old_path) != cache.end()) { - auto cached = cache[old_path]; - if (!cached.expired()) { - auto file = cached.lock(); - file->Open(new_path, "r+b"); - cache.erase(old_path); - cache[new_path] = file; + auto file = cache[old_path].lock(); + + if (!cache[old_path].expired()) { + file->Close(); + } + + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) { + return nullptr; } + + cache.erase(old_path); + file->Open(new_path, "r+b"); + cache[new_path] = file; + } else { + UNREACHABLE(); + return nullptr; } + return OpenFile(new_path, Mode::ReadWrite); } diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 256449aa7..4e7a0bec9 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1407,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { u32 supported_languages = 0; FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; - const auto res = pm.GetControlMetadata(); + const auto res = [this] { + const auto title_id = system.CurrentProcess()->GetTitleID(); + + FileSys::PatchManager pm{title_id}; + auto res = pm.GetControlMetadata(); + if (res.first != nullptr) { + return res; + } + + FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; + return pm_update.GetControlMetadata(); + }(); + if (res.first != nullptr) { supported_languages = res.first->GetSupportedLanguages(); } diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index f19affce7..11aa74828 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -121,11 +121,83 @@ public: {39, nullptr, "PrepareShutdown"}, {40, nullptr, "ListApplyDeltaTask"}, {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, - {42, nullptr, "Unknown1"}, - {43, nullptr, "Unknown2"}, - {44, nullptr, "Unknown3"}, - {45, nullptr, "Unknown4"}, - {46, nullptr, "Unknown5"}, + {42, nullptr, "Unknown42"}, + {43, nullptr, "Unknown43"}, + {44, nullptr, "Unknown44"}, + {45, nullptr, "Unknown45"}, + {46, nullptr, "Unknown46"}, + {47, nullptr, "Unknown47"}, + {48, nullptr, "Unknown48"}, + {49, nullptr, "Unknown49"}, + {50, nullptr, "Unknown50"}, + {51, nullptr, "Unknown51"}, + {52, nullptr, "Unknown52"}, + {53, nullptr, "Unknown53"}, + {54, nullptr, "Unknown54"}, + {55, nullptr, "Unknown55"}, + {56, nullptr, "Unknown56"}, + {57, nullptr, "Unknown57"}, + {58, nullptr, "Unknown58"}, + {59, nullptr, "Unknown59"}, + {60, nullptr, "Unknown60"}, + {61, nullptr, "Unknown61"}, + {62, nullptr, "Unknown62"}, + {63, nullptr, "Unknown63"}, + {64, nullptr, "Unknown64"}, + {65, nullptr, "Unknown65"}, + {66, nullptr, "Unknown66"}, + {67, nullptr, "Unknown67"}, + {68, nullptr, "Unknown68"}, + {69, nullptr, "Unknown69"}, + {70, nullptr, "Unknown70"}, + {71, nullptr, "Unknown71"}, + {72, nullptr, "Unknown72"}, + {73, nullptr, "Unknown73"}, + {74, nullptr, "Unknown74"}, + {75, nullptr, "Unknown75"}, + {76, nullptr, "Unknown76"}, + {77, nullptr, "Unknown77"}, + {78, nullptr, "Unknown78"}, + {79, nullptr, "Unknown79"}, + {80, nullptr, "Unknown80"}, + {81, nullptr, "Unknown81"}, + {82, nullptr, "Unknown82"}, + {83, nullptr, "Unknown83"}, + {84, nullptr, "Unknown84"}, + {85, nullptr, "Unknown85"}, + {86, nullptr, "Unknown86"}, + {87, nullptr, "Unknown87"}, + {88, nullptr, "Unknown88"}, + {89, nullptr, "Unknown89"}, + {90, nullptr, "Unknown90"}, + {91, nullptr, "Unknown91"}, + {92, nullptr, "Unknown92"}, + {93, nullptr, "Unknown93"}, + {94, nullptr, "Unknown94"}, + {95, nullptr, "Unknown95"}, + {96, nullptr, "Unknown96"}, + {97, nullptr, "Unknown97"}, + {98, nullptr, "Unknown98"}, + {99, nullptr, "Unknown99"}, + {100, nullptr, "Unknown100"}, + {101, nullptr, "Unknown101"}, + {102, nullptr, "Unknown102"}, + {103, nullptr, "Unknown103"}, + {104, nullptr, "Unknown104"}, + {105, nullptr, "Unknown105"}, + {106, nullptr, "Unknown106"}, + {107, nullptr, "Unknown107"}, + {108, nullptr, "Unknown108"}, + {109, nullptr, "Unknown109"}, + {110, nullptr, "Unknown110"}, + {111, nullptr, "Unknown111"}, + {112, nullptr, "Unknown112"}, + {113, nullptr, "Unknown113"}, + {114, nullptr, "Unknown114"}, + {115, nullptr, "Unknown115"}, + {116, nullptr, "Unknown116"}, + {117, nullptr, "Unknown117"}, + {118, nullptr, "Unknown118"}, }; // clang-format on @@ -142,6 +214,7 @@ public: {1, nullptr, "RefreshDebugAvailability"}, {2, nullptr, "ClearDebugResponse"}, {3, nullptr, "RegisterDebugResponse"}, + {4, nullptr, "IsLargeResourceAvailable"}, }; // clang-format on @@ -164,6 +237,8 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "RequestDeviceAuthenticationToken"}, {1, nullptr, "RequestCachedDeviceAuthenticationToken"}, + {2, nullptr, "RequestEdgeToken"}, + {3, nullptr, "RequestCachedEdgeToken"}, {100, nullptr, "RequestRegisterDeviceAccount"}, {101, nullptr, "RequestUnregisterDeviceAccount"}, {102, nullptr, "RequestDeviceAccountStatus"}, @@ -181,7 +256,8 @@ public: {305, nullptr, "RequestCreateVirtualAccount"}, {306, nullptr, "RequestDeviceLinkStatus"}, {400, nullptr, "GetAccountByVirtualAccount"}, - {500, nullptr, "RequestSyncTicket"}, + {401, nullptr, "GetVirtualAccount"}, + {500, nullptr, "RequestSyncTicketLegacy"}, {501, nullptr, "RequestDownloadTicket"}, {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, {503, nullptr, "RequestSyncTicket"}, diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp index f38d01084..8fa16fb08 100644 --- a/src/core/hle/service/npns/npns.cpp +++ b/src/core/hle/service/npns/npns.cpp @@ -30,6 +30,7 @@ public: {23, nullptr, "DestroyToken"}, {24, nullptr, "DestroyTokenWithApplicationId"}, {25, nullptr, "QueryIsTokenValid"}, + {26, nullptr, "ListenToMyApplicationId"}, {31, nullptr, "UploadTokenToBaaS"}, {32, nullptr, "DestroyTokenForBaaS"}, {33, nullptr, "CreateTokenForBaaS"}, diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 6cfa9666d..886450be2 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -104,7 +104,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {94, nullptr, "LaunchApplication"}, {95, nullptr, "GetApplicationLaunchInfo"}, {96, nullptr, "AcquireApplicationLaunchInfo"}, - {97, nullptr, "GetMainApplicationProgramIndex2"}, + {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"}, {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, {99, nullptr, "LaunchDevMenu"}, {100, nullptr, "ResetToFactorySettings"}, @@ -254,7 +254,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {2170, nullptr, "GetRightsEnvironmentStatus"}, {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, - {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"}, + {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"}, {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, @@ -446,8 +446,8 @@ IApplicationVersionInterface::IApplicationVersionInterface() IApplicationVersionInterface::~IApplicationVersionInterface() = default; -IContentManagerInterface::IContentManagerInterface() - : ServiceFramework{"IContentManagerInterface"} { +IContentManagementInterface::IContentManagementInterface() + : ServiceFramework{"IContentManagementInterface"} { // clang-format off static const FunctionInfo functions[] = { {11, nullptr, "CalculateApplicationOccupiedSize"}, @@ -464,7 +464,7 @@ IContentManagerInterface::IContentManagerInterface() RegisterHandlers(functions); } -IContentManagerInterface::~IContentManagerInterface() = default; +IContentManagementInterface::~IContentManagementInterface() = default; IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { // clang-format off @@ -546,7 +546,7 @@ NS::NS(const char* name) : ServiceFramework{name} { {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, - {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"}, + {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, }; // clang-format on @@ -573,9 +573,9 @@ public: {6, nullptr, "TerminateApplication"}, {7, nullptr, "PrepareLaunchProgramFromHost"}, {8, nullptr, "LaunchApplication"}, - {9, nullptr, "LaunchApplicationWithStorageId"}, - {10, nullptr, "TerminateApplication2"}, - {11, nullptr, "GetRunningApplicationProcessId"}, + {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, + {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, + {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"}, {13, nullptr, "CreateApplicationResourceForDevelop"}, {14, nullptr, "IsPreomiaForDevelop"}, @@ -637,6 +637,10 @@ public: {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"}, {10, nullptr, "NotifySystemUpdateForContentDelivery"}, {11, nullptr, "PrepareShutdown"}, + {12, nullptr, "Unknown12"}, + {13, nullptr, "Unknown13"}, + {14, nullptr, "Unknown14"}, + {15, nullptr, "Unknown15"}, {16, nullptr, "DestroySystemUpdateTask"}, {17, nullptr, "RequestSendSystemUpdate"}, {18, nullptr, "GetSendSystemUpdateProgress"}, diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 13a64ad88..c2554b878 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -40,10 +40,10 @@ public: ~IApplicationVersionInterface() override; }; -class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> { +class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { public: - explicit IContentManagerInterface(); - ~IContentManagerInterface() override; + explicit IContentManagementInterface(); + ~IContentManagementInterface() override; }; class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 6efdf1606..40838a225 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -163,7 +163,7 @@ PL_U::PL_U(Core::System& system) {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, {100, nullptr, "RequestApplicationFunctionAuthorization"}, - {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"}, + {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index c8ea6c661..deaf0808b 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -144,7 +144,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { } } -void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { +void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; pid = rp.Pop<u64>(); LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); @@ -154,7 +154,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); } -void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { +void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -187,13 +187,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) {4, &NVDRV::QueryEvent, "QueryEvent"}, {5, nullptr, "MapSharedMem"}, {6, &NVDRV::GetStatus, "GetStatus"}, - {7, nullptr, "ForceSetClientPID"}, - {8, &NVDRV::SetClientPID, "SetClientPID"}, + {7, nullptr, "SetAruidForTest"}, + {8, &NVDRV::SetAruid, "SetAruid"}, {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, {10, nullptr, "InitializeDevtools"}, {11, &NVDRV::Ioctl2, "Ioctl2"}, {12, &NVDRV::Ioctl3, "Ioctl3"}, - {13, &NVDRV::FinishInitialize, "FinishInitialize"}, + {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled, + "SetGraphicsFirmwareMemoryMarginEnabled"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 9269ce00c..72e17a728 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -29,8 +29,8 @@ private: void Close(Kernel::HLERequestContext& ctx); void Initialize(Kernel::HLERequestContext& ctx); void QueryEvent(Kernel::HLERequestContext& ctx); - void SetClientPID(Kernel::HLERequestContext& ctx); - void FinishInitialize(Kernel::HLERequestContext& ctx); + void SetAruid(Kernel::HLERequestContext& ctx); + void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); void GetStatus(Kernel::HLERequestContext& ctx); void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index b7b8b7a1b..73b37e805 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -10,19 +10,19 @@ namespace Service::Nvidia { NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { static const FunctionInfo functions[] = { - {0, &NVMEMP::Cmd0, "Cmd0"}, - {1, &NVMEMP::Cmd1, "Cmd1"}, + {0, &NVMEMP::Open, "Open"}, + {1, &NVMEMP::GetAruid, "GetAruid"}, }; RegisterHandlers(functions); } NVMEMP::~NVMEMP() = default; -void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { +void NVMEMP::Open(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } -void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) { +void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index 6eafb1346..c453ee4db 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -14,8 +14,8 @@ public: ~NVMEMP() override; private: - void Cmd0(Kernel::HLERequestContext& ctx); - void Cmd1(Kernel::HLERequestContext& ctx); + void Open(Kernel::HLERequestContext& ctx); + void GetAruid(Kernel::HLERequestContext& ctx); }; } // namespace Service::Nvidia diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp index 39cf05eba..c568a0adc 100644 --- a/src/core/hle/service/pcie/pcie.cpp +++ b/src/core/hle/service/pcie/pcie.cpp @@ -36,6 +36,9 @@ public: {18, nullptr, "ReleaseIrq"}, {19, nullptr, "SetIrqEnable"}, {20, nullptr, "SetAspmEnable"}, + {21, nullptr, "SetResetUponResumeEnable"}, + {22, nullptr, "Unknown22"}, + {23, nullptr, "Unknown23"}, }; // clang-format on diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index d6891a659..8bfc0276e 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -42,6 +42,9 @@ public: {24, nullptr, "GetModuleStateTable"}, {25, nullptr, "GetPowerDomainStateTable"}, {26, nullptr, "GetFuseInfo"}, + {27, nullptr, "GetDramId"}, + {28, nullptr, "IsPoweredOn"}, + {29, nullptr, "GetVoltage"}, }; // clang-format on diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 809eca0ab..f43122ad2 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -78,13 +78,13 @@ public: : ServiceFramework{"pm:dmnt"}, kernel(kernel) { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetDebugProcesses"}, - {1, nullptr, "StartDebugProcess"}, - {2, &DebugMonitor::GetTitlePid, "GetTitlePid"}, - {3, nullptr, "EnableDebugForTitleId"}, - {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"}, - {5, nullptr, "EnableDebugForApplication"}, - {6, nullptr, "DisableDebug"}, + {0, nullptr, "GetJitDebugProcessIdList"}, + {1, nullptr, "StartProcess"}, + {2, &DebugMonitor::GetProcessId, "GetProcessId"}, + {3, nullptr, "HookToCreateProcess"}, + {4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"}, + {5, nullptr, "HookToCreateApplicationProgress"}, + {6, nullptr, "ClearHook"}, }; // clang-format on @@ -92,7 +92,7 @@ public: } private: - void GetTitlePid(Kernel::HLERequestContext& ctx) { + void GetProcessId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto title_id = rp.PopRaw<u64>(); @@ -114,7 +114,7 @@ private: rb.Push((*process)->GetProcessID()); } - void GetApplicationPid(Kernel::HLERequestContext& ctx) { + void GetApplicationProcessId(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); GetApplicationPidGeneric(ctx, kernel.GetProcessList()); } @@ -163,15 +163,15 @@ public: : ServiceFramework{"pm:shell"}, kernel(kernel) { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "LaunchProcess"}, - {1, nullptr, "TerminateProcessByPid"}, - {2, nullptr, "TerminateProcessByTitleId"}, - {3, nullptr, "GetProcessEventWaiter"}, - {4, nullptr, "GetProcessEventType"}, + {0, nullptr, "LaunchProgram"}, + {1, nullptr, "TerminateProcess"}, + {2, nullptr, "TerminateProgram"}, + {3, nullptr, "GetProcessEventHandle"}, + {4, nullptr, "GetProcessEventInfo"}, {5, nullptr, "NotifyBootFinished"}, - {6, &Shell::GetApplicationPid, "GetApplicationPid"}, + {6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"}, {7, nullptr, "BoostSystemMemoryResourceLimit"}, - {8, nullptr, "EnableAdditionalSystemThreads"}, + {8, nullptr, "BoostApplicationThreadResourceLimit"}, {9, nullptr, "GetBootFinishedEventHandle"}, }; // clang-format on @@ -180,7 +180,7 @@ public: } private: - void GetApplicationPid(Kernel::HLERequestContext& ctx) { + void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); GetApplicationPidGeneric(ctx, kernel.GetProcessList()); } diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 67833d9af..cde3312da 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -42,6 +42,11 @@ public: {40101, nullptr, "SetUserAgreementCheckEnabled"}, {50100, nullptr, "ReadAllApplicationReportFiles"}, {90100, nullptr, "ReadAllReportFiles"}, + {90101, nullptr, "Unknown90101"}, + {90102, nullptr, "Unknown90102"}, + {90200, nullptr, "GetStatistics"}, + {90201, nullptr, "GetThroughputHistory"}, + {90300, nullptr, "GetLastUploadError"}, }; // clang-format on diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index 53ec6b031..99e1c9042 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp @@ -24,6 +24,8 @@ public: {4, nullptr, "Cancel"}, {5, nullptr, "PrintModuleInformation"}, {6, nullptr, "GetModuleInformation"}, + {10, nullptr, "Unknown10"}, + {11, nullptr, "Unknown11"}, }; // clang-format on diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp index 12d154ecf..6d9e6bd09 100644 --- a/src/core/hle/service/ptm/psm.cpp +++ b/src/core/hle/service/ptm/psm.cpp @@ -35,6 +35,7 @@ public: {15, nullptr, "GetBatteryAgePercentage"}, {16, nullptr, "GetBatteryChargeInfoEvent"}, {17, nullptr, "GetBatteryChargeInfoFields"}, + {18, nullptr, "GetBatteryChargeCalibratedEvent"}, }; // clang-format on diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 9cca84b31..972aaa6d9 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -12,7 +12,7 @@ namespace Service::SM { -void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { +void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); ctx.Session()->ConvertToDomain(); @@ -22,7 +22,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { rb.Push<u32>(1); // Converted sessions start with 1 request handler } -void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { +void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong // and that we probably want to actually make an entirely new Session, but we still need to // verify this on hardware. @@ -33,10 +33,10 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); } -void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); +void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); - DuplicateSession(ctx); + CloneCurrentObject(ctx); } void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { @@ -47,13 +47,14 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { rb.Push<u16>(0x1000); } +// https://switchbrew.org/wiki/IPC_Marshalling Controller::Controller() : ServiceFramework("IpcController") { static const FunctionInfo functions[] = { - {0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"}, - {0x00000001, nullptr, "ConvertDomainToSession"}, - {0x00000002, &Controller::DuplicateSession, "DuplicateSession"}, - {0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, - {0x00000004, &Controller::DuplicateSessionEx, "DuplicateSessionEx"}, + {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, + {1, nullptr, "CopyFromCurrentDomain"}, + {2, &Controller::CloneCurrentObject, "CloneCurrentObject"}, + {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, + {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h index dc66c9e37..180c6da50 100644 --- a/src/core/hle/service/sm/controller.h +++ b/src/core/hle/service/sm/controller.h @@ -14,9 +14,9 @@ public: ~Controller() override; private: - void ConvertSessionToDomain(Kernel::HLERequestContext& ctx); - void DuplicateSession(Kernel::HLERequestContext& ctx); - void DuplicateSessionEx(Kernel::HLERequestContext& ctx); + void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx); + void CloneCurrentObject(Kernel::HLERequestContext& ctx); + void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx); void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); }; diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index dc70fd6fe..40d781124 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -14,6 +14,7 @@ NSD::NSD(const char* name) : ServiceFramework(name) { {12, nullptr, "GetDeviceId"}, {13, nullptr, "DeleteSettings"}, {14, nullptr, "ImportSettings"}, + {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"}, {20, nullptr, "Resolve"}, {21, nullptr, "ResolveEx"}, {30, nullptr, "GetNasServiceSetting"}, @@ -28,6 +29,11 @@ NSD::NSD(const char* name) : ServiceFramework(name) { {60, nullptr, "ReadSaveDataFromFsForTest"}, {61, nullptr, "WriteSaveDataToFsForTest"}, {62, nullptr, "DeleteSaveDataOfFsForTest"}, + {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"}, + {64, nullptr, "SetWithoutDomainExchangeFqdns"}, + {100, nullptr, "GetApplicationServerEnvironmentType"}, + {101, nullptr, "SetApplicationServerEnvironmentType"}, + {102, nullptr, "DeleteApplicationServerEnvironmentType"}, }; // clang-format on diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 852e71e4b..e3017451f 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -7,7 +7,7 @@ namespace Service::Sockets { -void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { +void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { struct Parameters { u8 use_nsd_resolve; u32 unknown; @@ -29,15 +29,20 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { static const FunctionInfo functions[] = { {0, nullptr, "SetDnsAddressesPrivate"}, {1, nullptr, "GetDnsAddressPrivate"}, - {2, nullptr, "GetHostByName"}, - {3, nullptr, "GetHostByAddr"}, - {4, nullptr, "GetHostStringError"}, - {5, nullptr, "GetGaiStringError"}, - {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"}, - {7, nullptr, "GetNameInfo"}, - {8, nullptr, "RequestCancelHandle"}, - {9, nullptr, "CancelSocketCall"}, - {11, nullptr, "ClearDnsIpServerAddressArray"}, + {2, nullptr, "GetHostByNameRequest"}, + {3, nullptr, "GetHostByAddrRequest"}, + {4, nullptr, "GetHostStringErrorRequest"}, + {5, nullptr, "GetGaiStringErrorRequest"}, + {6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"}, + {7, nullptr, "GetNameInfoRequest"}, + {8, nullptr, "RequestCancelHandleRequest"}, + {9, nullptr, "CancelRequest"}, + {10, nullptr, "GetHostByNameRequestWithOptions"}, + {11, nullptr, "GetHostByAddrRequestWithOptions"}, + {12, nullptr, "GetAddrInfoRequestWithOptions"}, + {13, nullptr, "GetNameInfoRequestWithOptions"}, + {14, nullptr, "ResolverSetOptionRequest"}, + {15, nullptr, "ResolverGetOptionRequest"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index eda432903..acd3647bb 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -15,7 +15,7 @@ public: ~SFDNSRES() override; private: - void GetAddrInfo(Kernel::HLERequestContext& ctx); + void GetAddrInfoRequest(Kernel::HLERequestContext& ctx); }; } // namespace Service::Sockets diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index 70cb41905..773551464 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp @@ -9,35 +9,36 @@ namespace Service::SPL { SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { static const FunctionInfo functions[] = { {0, nullptr, "GetConfig"}, - {1, nullptr, "UserExpMod"}, + {1, nullptr, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, {5, nullptr, "SetConfig"}, {7, &SPL::GetRandomBytes, "GetRandomBytes"}, - {9, nullptr, "LoadSecureExpModKey"}, - {10, nullptr, "SecureExpMod"}, + {9, nullptr, "ImportLotusKey"}, + {10, nullptr, "DecryptLotusMessage"}, {11, nullptr, "IsDevelopment"}, {12, nullptr, "GenerateSpecificAesKey"}, - {13, nullptr, "DecryptPrivk"}, + {13, nullptr, "DecryptDeviceUniqueData"}, {14, nullptr, "DecryptAesKey"}, - {15, nullptr, "DecryptAesCtr"}, + {15, nullptr, "CryptAesCtr"}, {16, nullptr, "ComputeCmac"}, - {17, nullptr, "LoadRsaOaepKey"}, - {18, nullptr, "UnwrapRsaOaepWrappedTitleKey"}, + {17, nullptr, "ImportEsKey"}, + {18, nullptr, "UnwrapTitleKey"}, {19, nullptr, "LoadTitleKey"}, - {20, nullptr, "UnwrapAesWrappedTitleKey"}, - {21, nullptr, "LockAesEngine"}, - {22, nullptr, "UnlockAesEngine"}, - {23, nullptr, "GetSplWaitEvent"}, - {24, nullptr, "SetSharedData"}, - {25, nullptr, "GetSharedData"}, - {26, nullptr, "ImportSslRsaKey"}, - {27, nullptr, "SecureExpModWithSslKey"}, - {28, nullptr, "ImportEsRsaKey"}, - {29, nullptr, "SecureExpModWithEsKey"}, - {30, nullptr, "EncryptManuRsaKeyForImport"}, - {31, nullptr, "GetPackage2Hash"}, + {20, nullptr, "PrepareEsCommonKey"}, + {21, nullptr, "AllocateAesKeyslot"}, + {22, nullptr, "DeallocateAesKeySlot"}, + {23, nullptr, "GetAesKeyslotAvailableEvent"}, + {24, nullptr, "SetBootReason"}, + {25, nullptr, "GetBootReason"}, + {26, nullptr, "DecryptAndStoreSslClientCertKey"}, + {27, nullptr, "ModularExponentiateWithSslClientCertKey"}, + {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"}, + {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"}, + {30, nullptr, "ReencryptDeviceUniqueData "}, + {31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash? + {32, nullptr, "LoadPreparedAesKey"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 4cf58a61a..13e4b3818 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -90,6 +90,13 @@ public: : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} { static const FunctionInfo functions[] = { {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, + {2, nullptr, "GetTestOffset"}, + {3, nullptr, "SetTestOffset"}, + {100, nullptr, "GetRtcValue"}, + {101, nullptr, "IsRtcResetDetected"}, + {102, nullptr, "GetSetupResultValue"}, + {200, nullptr, "GetInternalOffset"}, + {201, nullptr, "SetInternalOffset"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index 58a9845fc..d033f8603 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -20,7 +20,7 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "GetDsEndpoint"}, {1, nullptr, "GetSetupEvent"}, - {2, nullptr, "Unknown"}, + {2, nullptr, "Unknown2"}, {3, nullptr, "EnableInterface"}, {4, nullptr, "DisableInterface"}, {5, nullptr, "CtrlInPostBufferAsync"}, @@ -55,6 +55,7 @@ public: {9, nullptr, "SetBinaryObjectStore"}, {10, nullptr, "Enable"}, {11, nullptr, "Disable"}, + {12, nullptr, "Unknown12"}, }; // clang-format on @@ -69,13 +70,13 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "Open"}, {1, nullptr, "Close"}, - {2, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, {3, nullptr, "Populate"}, {4, nullptr, "PostBufferAsync"}, {5, nullptr, "GetXferReport"}, {6, nullptr, "PostBufferMultiAsync"}, - {7, nullptr, "Unknown3"}, - {8, nullptr, "Unknown4"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -88,13 +89,13 @@ public: explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, + {0, nullptr, "Unknown0"}, {1, nullptr, "SetInterface"}, {2, nullptr, "GetInterface"}, {3, nullptr, "GetAlternateInterface"}, {4, nullptr, "GetCurrentFrame"}, {5, nullptr, "CtrlXferAsync"}, - {6, nullptr, "Unknown2"}, + {6, nullptr, "Unknown6"}, {7, nullptr, "GetCtrlXferReport"}, {8, nullptr, "ResetDevice"}, {9, nullptr, "OpenUsbEp"}, @@ -118,7 +119,7 @@ public: {5, nullptr, "DestroyInterfaceAvailableEvent"}, {6, nullptr, "GetInterfaceStateChangeEvent"}, {7, nullptr, "AcquireUsbIf"}, - {8, nullptr, "Unknown1"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -179,8 +180,8 @@ public: {4, nullptr, "GetFwRevision"}, {5, nullptr, "GetManufacturerId"}, {6, nullptr, "GetDeviceId"}, - {7, nullptr, "Unknown1"}, - {8, nullptr, "Unknown2"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -215,12 +216,12 @@ public: explicit USB_PM() : ServiceFramework{"usb:pm"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, }; // clang-format on diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 552a5e4ef..ea7b4ae13 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -700,6 +700,7 @@ public: {3215, nullptr, "SetDisplayGamma"}, {3216, nullptr, "GetDisplayCmuLuma"}, {3217, nullptr, "SetDisplayCmuLuma"}, + {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, {8225, nullptr, "GetSharedBufferMemoryHandleId"}, {8250, nullptr, "OpenSharedLayer"}, {8251, nullptr, "CloseSharedLayer"}, @@ -785,6 +786,7 @@ public: {2300, nullptr, "AcquireLayerTexturePresentingEvent"}, {2301, nullptr, "ReleaseLayerTexturePresentingEvent"}, {2302, nullptr, "GetDisplayHotplugEvent"}, + {2303, nullptr, "GetDisplayModeChangedEvent"}, {2402, nullptr, "GetDisplayHotplugState"}, {2501, nullptr, "GetCompositorErrorInfo"}, {2601, nullptr, "GetDisplayErrorEvent"}, diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 9d5ceb608..6b7329345 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -12,6 +12,7 @@ VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { static const FunctionInfo functions[] = { {0, &VI_U::GetDisplayService, "GetDisplayService"}, + {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp index 2654594c1..0260d7dcf 100644 --- a/src/core/hle/service/wlan/wlan.cpp +++ b/src/core/hle/service/wlan/wlan.cpp @@ -15,34 +15,37 @@ public: explicit WLANInfra() : ServiceFramework{"wlan:inf"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, + {0, nullptr, "OpenMode"}, + {1, nullptr, "CloseMode"}, {2, nullptr, "GetMacAddress"}, {3, nullptr, "StartScan"}, {4, nullptr, "StopScan"}, {5, nullptr, "Connect"}, {6, nullptr, "CancelConnect"}, {7, nullptr, "Disconnect"}, - {8, nullptr, "Unknown3"}, - {9, nullptr, "Unknown4"}, + {8, nullptr, "GetConnectionEvent"}, + {9, nullptr, "GetConnectionStatus"}, {10, nullptr, "GetState"}, {11, nullptr, "GetScanResult"}, {12, nullptr, "GetRssi"}, {13, nullptr, "ChangeRxAntenna"}, - {14, nullptr, "Unknown5"}, - {15, nullptr, "Unknown6"}, + {14, nullptr, "GetFwVersion"}, + {15, nullptr, "RequestSleep"}, {16, nullptr, "RequestWakeUp"}, {17, nullptr, "RequestIfUpDown"}, - {18, nullptr, "Unknown7"}, - {19, nullptr, "Unknown8"}, - {20, nullptr, "Unknown9"}, - {21, nullptr, "Unknown10"}, - {22, nullptr, "Unknown11"}, - {23, nullptr, "Unknown12"}, - {24, nullptr, "Unknown13"}, - {25, nullptr, "Unknown14"}, - {26, nullptr, "Unknown15"}, - {27, nullptr, "Unknown16"}, + {18, nullptr, "Unknown18"}, + {19, nullptr, "Unknown19"}, + {20, nullptr, "Unknown20"}, + {21, nullptr, "Unknown21"}, + {22, nullptr, "Unknown22"}, + {23, nullptr, "Unknown23"}, + {24, nullptr, "Unknown24"}, + {25, nullptr, "Unknown25"}, + {26, nullptr, "Unknown26"}, + {27, nullptr, "Unknown27"}, + {28, nullptr, "Unknown28"}, + {29, nullptr, "Unknown29"}, + {30, nullptr, "Unknown30"}, }; // clang-format on @@ -55,12 +58,12 @@ public: explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, {6, nullptr, "GetMacAddress"}, {7, nullptr, "CreateBss"}, {8, nullptr, "DestroyBss"}, @@ -72,38 +75,42 @@ public: {14, nullptr, "CancelJoin"}, {15, nullptr, "Disconnect"}, {16, nullptr, "SetBeaconLostCount"}, - {17, nullptr, "Unknown7"}, - {18, nullptr, "Unknown8"}, - {19, nullptr, "Unknown9"}, + {17, nullptr, "Unknown17"}, + {18, nullptr, "Unknown18"}, + {19, nullptr, "Unknown19"}, {20, nullptr, "GetBssIndicationEvent"}, {21, nullptr, "GetBssIndicationInfo"}, {22, nullptr, "GetState"}, {23, nullptr, "GetAllowedChannels"}, {24, nullptr, "AddIe"}, {25, nullptr, "DeleteIe"}, - {26, nullptr, "Unknown10"}, - {27, nullptr, "Unknown11"}, + {26, nullptr, "Unknown26"}, + {27, nullptr, "Unknown27"}, {28, nullptr, "CreateRxEntry"}, {29, nullptr, "DeleteRxEntry"}, - {30, nullptr, "Unknown12"}, - {31, nullptr, "Unknown13"}, + {30, nullptr, "Unknown30"}, + {31, nullptr, "Unknown31"}, {32, nullptr, "AddMatchingDataToRxEntry"}, {33, nullptr, "RemoveMatchingDataFromRxEntry"}, {34, nullptr, "GetScanResult"}, - {35, nullptr, "Unknown14"}, + {35, nullptr, "Unknown35"}, {36, nullptr, "SetActionFrameWithBeacon"}, {37, nullptr, "CancelActionFrameWithBeacon"}, {38, nullptr, "CreateRxEntryForActionFrame"}, {39, nullptr, "DeleteRxEntryForActionFrame"}, - {40, nullptr, "Unknown15"}, - {41, nullptr, "Unknown16"}, + {40, nullptr, "Unknown40"}, + {41, nullptr, "Unknown41"}, {42, nullptr, "CancelGetActionFrame"}, {43, nullptr, "GetRssi"}, - {44, nullptr, "Unknown17"}, - {45, nullptr, "Unknown18"}, - {46, nullptr, "Unknown19"}, - {47, nullptr, "Unknown20"}, - {48, nullptr, "Unknown21"}, + {44, nullptr, "Unknown44"}, + {45, nullptr, "Unknown45"}, + {46, nullptr, "Unknown46"}, + {47, nullptr, "Unknown47"}, + {48, nullptr, "Unknown48"}, + {49, nullptr, "Unknown49"}, + {50, nullptr, "Unknown50"}, + {51, nullptr, "Unknown51"}, + {52, nullptr, "Unknown52"}, }; // clang-format on @@ -142,18 +149,19 @@ public: explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, {6, nullptr, "GetMacAddress"}, {7, nullptr, "SwitchTsfTimerFunction"}, - {8, nullptr, "Unknown7"}, - {9, nullptr, "Unknown8"}, - {10, nullptr, "Unknown9"}, - {11, nullptr, "Unknown10"}, + {8, nullptr, "Unknown8"}, + {9, nullptr, "Unknown9"}, + {10, nullptr, "Unknown10"}, + {11, nullptr, "Unknown11"}, + {12, nullptr, "Unknown12"}, }; // clang-format on diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 3bd76dd23..317c25bad 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -30,7 +30,8 @@ if(SDL2_FOUND) target_compile_definitions(input_common PRIVATE HAVE_SDL2) endif() -target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) +target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR}) +target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES}) create_target_directory_groups(input_common) target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 6d9f4d9eb..c031fc22a 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -4,6 +4,7 @@ #include <chrono> #include <thread> +#include <libusb.h> #include "common/logging/log.h" #include "input_common/gcadapter/gc_adapter.h" diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index b1c2a1958..1337c260e 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -8,10 +8,13 @@ #include <mutex> #include <thread> #include <unordered_map> -#include <libusb.h> #include "common/common_types.h" #include "common/threadsafe_queue.h" +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + namespace GCAdapter { enum { diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index fd0af1019..b9d5d0ec3 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,7 +4,6 @@ #include <memory> #include <thread> -#include <libusb.h> #include "common/param_package.h" #include "input_common/analog_from_button.h" #include "input_common/gcadapter/gc_adapter.h" diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 380ed532b..7625871c2 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -332,23 +332,23 @@ private: if constexpr (has_extended_dynamic_state) { // With extended dynamic states we can specify the length and stride of a vertex buffer - // std::array<VkDeviceSize, N> sizes; + std::array<VkDeviceSize, N> sizes; std::array<u16, N> strides; - // std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); + std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin()); if constexpr (is_indexed) { scheduler.Record( - [buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) { + [buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) { cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type); cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), - offsets.data(), nullptr, + offsets.data(), sizes.data(), ExpandStrides(strides).data()); }); } else { - scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) { + scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) { cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), - offsets.data(), nullptr, + offsets.data(), sizes.data(), ExpandStrides(strides).data()); }); } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 6b25a7fa0..ff7d9c1fa 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -98,11 +98,13 @@ add_executable(yuzu game_list_p.h game_list_worker.cpp game_list_worker.h + hotkeys.cpp + hotkeys.h + install_dialog.cpp + install_dialog.h loading_screen.cpp loading_screen.h loading_screen.ui - hotkeys.cpp - hotkeys.h main.cpp main.h main.ui diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 1fb62d1cf..20316c9cc 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -65,6 +65,8 @@ void ConfigureGeneral::ApplyConfiguration() { Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == Qt::Checked); Settings::values.frame_limit.SetValue(ui->frame_limit->value()); + } + if (Settings::values.use_multi_core.UsingGlobal()) { Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked()); } } else { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index bfb600df0..ab7fc7a24 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -531,8 +531,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { UISettings::GameDir& game_dir = *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); - QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up")); - QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down ")); + QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up")); + QAction* move_down = context_menu.addAction(tr("\u25bc Move Down")); QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location")); const int row = selected.row(); diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp new file mode 100644 index 000000000..06b0b1874 --- /dev/null +++ b/src/yuzu/install_dialog.cpp @@ -0,0 +1,72 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QCheckBox> +#include <QDialogButtonBox> +#include <QFileInfo> +#include <QHBoxLayout> +#include <QLabel> +#include <QListWidget> +#include <QVBoxLayout> +#include "yuzu/install_dialog.h" +#include "yuzu/uisettings.h" + +InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) { + file_list = new QListWidget(this); + + for (const QString& file : files) { + QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list); + item->setData(Qt::UserRole, file); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Checked); + } + + file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10); + + vbox_layout = new QVBoxLayout; + + hbox_layout = new QHBoxLayout; + + description = new QLabel(tr("Please confirm these are the files you wish to install.")); + + update_description = + new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one.")); + + buttons = new QDialogButtonBox; + buttons->addButton(QDialogButtonBox::Cancel); + buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole); + + connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject); + + hbox_layout->addWidget(buttons); + + vbox_layout->addWidget(description); + vbox_layout->addWidget(update_description); + vbox_layout->addWidget(file_list); + vbox_layout->addLayout(hbox_layout); + + setLayout(vbox_layout); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Install Files to NAND")); +} + +InstallDialog::~InstallDialog() = default; + +QStringList InstallDialog::GetFiles() const { + QStringList files; + + for (int i = 0; i < file_list->count(); ++i) { + const QListWidgetItem* item = file_list->item(i); + if (item->checkState() == Qt::Checked) { + files.append(item->data(Qt::UserRole).toString()); + } + } + + return files; +} + +int InstallDialog::GetMinimumWidth() const { + return file_list->width(); +} diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h new file mode 100644 index 000000000..e4aba1b06 --- /dev/null +++ b/src/yuzu/install_dialog.h @@ -0,0 +1,36 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QDialog> + +class QCheckBox; +class QDialogButtonBox; +class QHBoxLayout; +class QLabel; +class QListWidget; +class QVBoxLayout; + +class InstallDialog : public QDialog { + Q_OBJECT + +public: + explicit InstallDialog(QWidget* parent, const QStringList& files); + ~InstallDialog() override; + + QStringList GetFiles() const; + bool ShouldOverwriteFiles() const; + int GetMinimumWidth() const; + +private: + QListWidget* file_list; + + QVBoxLayout* vbox_layout; + QHBoxLayout* hbox_layout; + + QLabel* description; + QLabel* update_description; + QDialogButtonBox* buttons; +}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4d501a8f9..432379705 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" +#include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" #include "yuzu/uisettings.h" @@ -847,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::OpenPerGameGeneralRequested, this, &GMainWindow::OnGameListOpenPerGameProperties); + connect(this, &GMainWindow::UpdateInstallProgress, this, + &GMainWindow::IncrementInstallProgress); + connect(this, &GMainWindow::EmulationStarting, render_window, &GRenderWindow::OnEmulationStarting); connect(this, &GMainWindow::EmulationStopping, render_window, @@ -1593,187 +1597,255 @@ void GMainWindow::OnMenuLoadFolder() { } } +void GMainWindow::IncrementInstallProgress() { + install_progress->setValue(install_progress->value() + 1); +} + void GMainWindow::OnMenuInstallToNAND() { const QString file_filter = tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " - "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " + "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge " "Image (*.xci)"); - QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), - UISettings::values.roms_path, file_filter); - if (filename.isEmpty()) { + QStringList filenames = QFileDialog::getOpenFileNames( + this, tr("Install Files"), UISettings::values.roms_path, file_filter); + + if (filenames.isEmpty()) { return; } + InstallDialog installDialog(this, filenames); + if (installDialog.exec() == QDialog::Rejected) { + return; + } + + const QStringList files = installDialog.GetFiles(); + + if (files.isEmpty()) { + return; + } + + int remaining = filenames.size(); + + // This would only overflow above 2^43 bytes (8.796 TB) + int total_size = 0; + for (const QString& file : files) { + total_size += static_cast<int>(QFile(file).size() / 0x1000); + } + if (total_size < 0) { + LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting."); + return; + } + + QStringList new_files{}; // Newly installed files that do not yet exist in the NAND + QStringList overwritten_files{}; // Files that overwrote those existing in the NAND + QStringList failed_files{}; // Files that failed to install due to errors + + ui.action_Install_File_NAND->setEnabled(false); + + install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this); + install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & + ~Qt::WindowMaximizeButtonHint); + install_progress->setAttribute(Qt::WA_DeleteOnClose, true); + install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40); + install_progress->show(); + + for (const QString& file : files) { + install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining)); + install_progress->setLabelText( + tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); + + QFuture<InstallResult> future; + InstallResult result; + + if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + + future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); }); + + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + + result = future.result(); + + } else { + result = InstallNCA(file); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + switch (result) { + case InstallResult::Success: + new_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Overwrite: + overwritten_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Failure: + failed_files.append(QFileInfo(file).fileName()); + break; + } + + --remaining; + } + + install_progress->close(); + + const QString install_results = + (new_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) were newly installed\n", "", new_files.size())) + + (overwritten_files.isEmpty() + ? QStringLiteral("") + : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) + + (failed_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) failed to install\n", "", failed_files.size())); + + QMessageBox::information(this, tr("Install Results"), install_results); + game_list->PopulateAsync(UISettings::values.game_dirs); + FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + + "game_list"); + ui.action_Install_File_NAND->setEnabled(true); +} + +InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, std::size_t block_size) { - if (src == nullptr || dest == nullptr) + if (src == nullptr || dest == nullptr) { return false; - if (!dest->Resize(src->GetSize())) + } + if (!dest->Resize(src->GetSize())) { return false; + } std::array<u8, 0x1000> buffer{}; - const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size()); - - QProgressDialog progress( - tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())), - tr("Cancel"), 0, progress_maximum, this); - progress.setWindowModality(Qt::WindowModal); for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - if (progress.wasCanceled()) { + if (install_progress->wasCanceled()) { dest->Resize(0); return false; } - const int progress_value = static_cast<int>(i / buffer.size()); - progress.setValue(progress_value); + emit UpdateInstallProgress(); const auto read = src->Read(buffer.data(), buffer.size(), i); dest->Write(buffer.data(), read, i); } - return true; }; - const auto success = [this]() { - QMessageBox::information(this, tr("Successfully Installed"), - tr("The file was successfully installed.")); - game_list->PopulateAsync(UISettings::values.game_dirs); - FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + - DIR_SEP + "game_list"); - }; - - const auto failed = [this]() { - QMessageBox::warning( - this, tr("Failed to Install"), - tr("There was an error while attempting to install the provided file. It " - "could have an incorrect format or be missing metadata. Please " - "double-check your file and try again.")); - }; - - const auto overwrite = [this]() { - return QMessageBox::question(this, tr("Failed to Install"), - tr("The file you are attempting to install already exists " - "in the cache. Would you like to overwrite it?")) == - QMessageBox::Yes; - }; - - if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || - filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - std::shared_ptr<FileSys::NSP> nsp; - if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - nsp = std::make_shared<FileSys::NSP>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (nsp->IsExtractedType()) - failed(); - } else { - const auto xci = std::make_shared<FileSys::XCI>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - nsp = xci->GetSecurePartitionNSP(); - } - - if (nsp->GetStatus() != Loader::ResultStatus::Success) { - failed(); - return; - } - const auto res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, false, qt_raw_copy); - if (res == FileSys::InstallResult::Success) { - success(); - } else { - if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } - } - } else { - failed(); - } + std::shared_ptr<FileSys::NSP> nsp; + if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + nsp = std::make_shared<FileSys::NSP>( + vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + if (nsp->IsExtractedType()) { + return InstallResult::Failure; } } else { - const auto nca = std::make_shared<FileSys::NCA>( + const auto xci = std::make_shared<FileSys::XCI>( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - const auto id = nca->GetStatus(); + nsp = xci->GetSecurePartitionNSP(); + } - // Game updates necessary are missing base RomFS - if (id != Loader::ResultStatus::Success && - id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { - failed(); - return; - } + if (nsp->GetStatus() != Loader::ResultStatus::Success) { + return InstallResult::Failure; + } + const auto res = + Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( + *nsp, true, qt_raw_copy); + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; + } +} - const QStringList tt_options{tr("System Application"), - tr("System Archive"), - tr("System Application Update"), - tr("Firmware Package (Type A)"), - tr("Firmware Package (Type B)"), - tr("Game"), - tr("Game Update"), - tr("Game DLC"), - tr("Delta Title")}; - bool ok; - const auto item = QInputDialog::getItem( - this, tr("Select NCA Install Type..."), - tr("Please select the type of title you would like to install this NCA as:\n(In " - "most instances, the default 'Game' is fine.)"), - tt_options, 5, false, &ok); - - auto index = tt_options.indexOf(item); - if (!ok || index == -1) { - QMessageBox::warning(this, tr("Failed to Install"), - tr("The title type you selected for the NCA is invalid.")); - return; +InstallResult GMainWindow::InstallNCA(const QString& filename) { + const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, + const FileSys::VirtualFile& dest, std::size_t block_size) { + if (src == nullptr || dest == nullptr) { + return false; } - - // If index is equal to or past Game, add the jump in TitleType. - if (index >= 5) { - index += static_cast<size_t>(FileSys::TitleType::Application) - - static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + if (!dest->Resize(src->GetSize())) { + return false; } - FileSys::InstallResult res; - if (index >= static_cast<s32>(FileSys::TitleType::Application)) { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } else { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetSystemNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } + std::array<u8, 0x1000> buffer{}; - if (res == FileSys::InstallResult::Success) { - success(); - } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), - true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { + if (install_progress->wasCanceled()) { + dest->Resize(0); + return false; } - } else { - failed(); + + emit UpdateInstallProgress(); + + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); } + return true; + }; + + const auto nca = + std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + const auto id = nca->GetStatus(); + + // Game updates necessary are missing base RomFS + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + return InstallResult::Failure; + } + + const QStringList tt_options{tr("System Application"), + tr("System Archive"), + tr("System Application Update"), + tr("Firmware Package (Type A)"), + tr("Firmware Package (Type B)"), + tr("Game"), + tr("Game Update"), + tr("Game DLC"), + tr("Delta Title")}; + bool ok; + const auto item = QInputDialog::getItem( + this, tr("Select NCA Install Type..."), + tr("Please select the type of title you would like to install this NCA as:\n(In " + "most instances, the default 'Game' is fine.)"), + tt_options, 5, false, &ok); + + auto index = tt_options.indexOf(item); + if (!ok || index == -1) { + QMessageBox::warning(this, tr("Failed to Install"), + tr("The title type you selected for the NCA is invalid.")); + return InstallResult::Failure; + } + + // If index is equal to or past Game, add the jump in TitleType. + if (index >= 5) { + index += static_cast<size_t>(FileSys::TitleType::Application) - + static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + } + + FileSys::InstallResult res; + if (index >= static_cast<s32>(FileSys::TitleType::Application)) { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetUserNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } else { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetSystemNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } + + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; } } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8e3d39c38..adff65fb5 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -28,6 +28,7 @@ class MicroProfileDialog; class ProfilerWidget; class QLabel; class QPushButton; +class QProgressDialog; class WaitTreeWidget; enum class GameListOpenTarget; class GameListPlaceholder; @@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget { SDMC, }; +enum class InstallResult { + Success, + Overwrite, + Failure, +}; + enum class ReinitializeKeyBehavior { NoWarning, Warning, @@ -102,6 +109,8 @@ signals: // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); + void UpdateInstallProgress(); + void ErrorDisplayFinished(); void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); @@ -198,6 +207,7 @@ private slots: void OnGameListOpenPerGameProperties(const std::string& file); void OnMenuLoadFile(); void OnMenuLoadFolder(); + void IncrementInstallProgress(); void OnMenuInstallToNAND(); void OnMenuRecentFile(); void OnConfigure(); @@ -218,6 +228,8 @@ private slots: private: std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); + InstallResult InstallNSPXCI(const QString& filename); + InstallResult InstallNCA(const QString& filename); void UpdateWindowTitle(const std::string& title_name = {}, const std::string& title_version = {}); void UpdateStatusBar(); @@ -272,6 +284,9 @@ private: HotkeyRegistry hotkey_registry; + // Install progress dialog + QProgressDialog* install_progress; + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index bee6e107e..c3a1d715e 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -130,7 +130,7 @@ <bool>true</bool> </property> <property name="text"> - <string>Install File to NAND...</string> + <string>Install Files to NAND...</string> </property> </action> <action name="action_Load_File"> |