summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--CMakeModules/DownloadExternals.cmake18
-rw-r--r--externals/CMakeLists.txt14
-rw-r--r--src/CMakeLists.txt19
-rw-r--r--src/android/app/build.gradle.kts2
-rw-r--r--src/android/app/src/main/AndroidManifest.xml1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt35
-rw-r--r--src/android/app/src/main/jni/native.cpp44
-rw-r--r--src/common/swap.h5
-rw-r--r--src/core/file_sys/registered_cache.cpp37
-rw-r--r--src/core/hle/kernel/k_process.cpp25
-rw-r--r--src/core/hle/kernel/k_process.h7
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp4
-rw-r--r--src/core/hle/service/service.h4
-rw-r--r--src/core/hle/service/sockets/bsd.cpp5
-rw-r--r--src/core/hle/service/sockets/bsd.h3
-rw-r--r--src/core/hle/service/ssl/ssl.cpp10
-rw-r--r--src/core/hle/service/ssl/ssl_backend_openssl.cpp3
-rw-r--r--src/core/hle/service/ssl/ssl_backend_schannel.cpp25
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp2
-rw-r--r--src/core/loader/kip.cpp2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/input_common/input_poller.cpp10
-rw-r--r--src/video_core/macro/macro.cpp24
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp7
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_library.cpp16
-rw-r--r--src/web_service/verify_user_jwt.cpp1
-rw-r--r--src/yuzu/CMakeLists.txt12
-rw-r--r--src/yuzu/configuration/shared_widget.cpp1
-rw-r--r--src/yuzu/game_list_worker.cpp23
-rw-r--r--src/yuzu/main.cpp38
-rw-r--r--src/yuzu/main.h1
36 files changed, 323 insertions, 106 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af9f394f1..7858d0450 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,7 +49,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
49 49
50option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) 50option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
51 51
52cmake_dependent_option(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF) 52CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
53 53
54CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF) 54CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
55 55
@@ -63,6 +63,8 @@ option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
63 63
64CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) 64CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
65 65
66CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
67
66set(DEFAULT_ENABLE_OPENSSL ON) 68set(DEFAULT_ENABLE_OPENSSL ON)
67if (ANDROID OR WIN32 OR APPLE) 69if (ANDROID OR WIN32 OR APPLE)
68 # - Windows defaults to the Schannel backend. 70 # - Windows defaults to the Schannel backend.
diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake
index 972f5ca74..a52148bd8 100644
--- a/CMakeModules/DownloadExternals.cmake
+++ b/CMakeModules/DownloadExternals.cmake
@@ -36,3 +36,21 @@ endif()
36message(STATUS "Using bundled binaries at ${prefix}") 36message(STATUS "Using bundled binaries at ${prefix}")
37set(${prefix_var} "${prefix}" PARENT_SCOPE) 37set(${prefix_var} "${prefix}" PARENT_SCOPE)
38endfunction() 38endfunction()
39
40function(download_moltenvk_external platform version)
41 set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
42 set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
43 if (NOT EXISTS ${MOLTENVK_DIR})
44 if (NOT EXISTS ${MOLTENVK_TAR})
45 file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
46 ${MOLTENVK_TAR} SHOW_PROGRESS)
47 endif()
48
49 execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
50 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
51 endif()
52
53 # Add the MoltenVK library path to the prefix so find_library can locate it.
54 list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
55 set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
56endfunction()
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 1f7cd598e..82a6da9fd 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -42,6 +42,11 @@ endif()
42# mbedtls 42# mbedtls
43add_subdirectory(mbedtls) 43add_subdirectory(mbedtls)
44target_include_directories(mbedtls PUBLIC ./mbedtls/include) 44target_include_directories(mbedtls PUBLIC ./mbedtls/include)
45if (NOT MSVC)
46 target_compile_options(mbedcrypto PRIVATE
47 -Wno-unused-but-set-variable
48 -Wno-string-concatenation)
49endif()
45 50
46# MicroProfile 51# MicroProfile
47add_library(microprofile INTERFACE) 52add_library(microprofile INTERFACE)
@@ -94,6 +99,12 @@ if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
94 set(BUILD_TOOLS OFF) 99 set(BUILD_TOOLS OFF)
95 add_subdirectory(cubeb) 100 add_subdirectory(cubeb)
96 add_library(cubeb::cubeb ALIAS cubeb) 101 add_library(cubeb::cubeb ALIAS cubeb)
102 if (NOT MSVC)
103 if (TARGET speex)
104 target_compile_options(speex PRIVATE -Wno-sign-compare)
105 endif()
106 target_compile_options(cubeb PRIVATE -Wno-implicit-const-int-float-conversion)
107 endif()
97endif() 108endif()
98 109
99# DiscordRPC 110# DiscordRPC
@@ -151,6 +162,9 @@ endif()
151if (NOT TARGET LLVM::Demangle) 162if (NOT TARGET LLVM::Demangle)
152 add_library(demangle demangle/ItaniumDemangle.cpp) 163 add_library(demangle demangle/ItaniumDemangle.cpp)
153 target_include_directories(demangle PUBLIC ./demangle) 164 target_include_directories(demangle PUBLIC ./demangle)
165 if (NOT MSVC)
166 target_compile_options(demangle PRIVATE -Wno-deprecated-declarations) # std::is_pod
167 endif()
154 add_library(LLVM::Demangle ALIAS demangle) 168 add_library(LLVM::Demangle ALIAS demangle)
155endif() 169endif()
156 170
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7bb88c8ea..6068c7a1f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -114,16 +114,19 @@ else()
114 -Wno-attributes 114 -Wno-attributes
115 -Wno-invalid-offsetof 115 -Wno-invalid-offsetof
116 -Wno-unused-parameter 116 -Wno-unused-parameter
117
118 $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
119 $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
120 $<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
121 $<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
122 $<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
123 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
124 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
125 ) 117 )
126 118
119 if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
120 add_compile_options(
121 -Wno-braced-scalar-init
122 -Wno-unused-private-field
123 -Wno-nullability-completeness
124 -Werror=shadow-uncaptured-local
125 -Werror=implicit-fallthrough
126 -Werror=type-limits
127 )
128 endif()
129
127 if (ARCHITECTURE_x86_64) 130 if (ARCHITECTURE_x86_64)
128 add_compile_options("-mcx16") 131 add_compile_options("-mcx16")
129 add_compile_options("-fwrapv") 132 add_compile_options("-fwrapv")
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index a8db70511..fe79a701c 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -95,6 +95,7 @@ android {
95 // builds a release build that doesn't need signing 95 // builds a release build that doesn't need signing
96 // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. 96 // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
97 register("relWithDebInfo") { 97 register("relWithDebInfo") {
98 isDefault = true
98 resValue("string", "app_name_suffixed", "yuzu Debug Release") 99 resValue("string", "app_name_suffixed", "yuzu Debug Release")
99 signingConfig = signingConfigs.getByName("debug") 100 signingConfig = signingConfigs.getByName("debug")
100 isMinifyEnabled = true 101 isMinifyEnabled = true
@@ -122,6 +123,7 @@ android {
122 flavorDimensions.add("version") 123 flavorDimensions.add("version")
123 productFlavors { 124 productFlavors {
124 create("mainline") { 125 create("mainline") {
126 isDefault = true
125 dimension = "version" 127 dimension = "version"
126 buildConfigField("Boolean", "PREMIUM", "false") 128 buildConfigField("Boolean", "PREMIUM", "false")
127 } 129 }
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index 6184f3eb6..36e2dac98 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -25,6 +25,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
25 android:hasFragileUserData="false" 25 android:hasFragileUserData="false"
26 android:supportsRtl="true" 26 android:supportsRtl="true"
27 android:isGame="true" 27 android:isGame="true"
28 android:appCategory="game"
28 android:localeConfig="@xml/locales_config" 29 android:localeConfig="@xml/locales_config"
29 android:banner="@drawable/tv_banner" 30 android:banner="@drawable/tv_banner"
30 android:extractNativeLibs="true" 31 android:extractNativeLibs="true"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
index f8e7eeca7..f71d0a098 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
@@ -11,6 +11,7 @@ import kotlinx.serialization.json.Json
11import org.yuzu.yuzu_emu.NativeLibrary 11import org.yuzu.yuzu_emu.NativeLibrary
12import org.yuzu.yuzu_emu.YuzuApplication 12import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.model.Game 13import org.yuzu.yuzu_emu.model.Game
14import org.yuzu.yuzu_emu.model.MinimalDocumentFile
14 15
15object GameHelper { 16object GameHelper {
16 const val KEY_GAME_PATH = "game_path" 17 const val KEY_GAME_PATH = "game_path"
@@ -29,15 +30,7 @@ object GameHelper {
29 // Ensure keys are loaded so that ROM metadata can be decrypted. 30 // Ensure keys are loaded so that ROM metadata can be decrypted.
30 NativeLibrary.reloadKeys() 31 NativeLibrary.reloadKeys()
31 32
32 val children = FileUtil.listFiles(context, gamesUri) 33 addGamesRecursive(games, FileUtil.listFiles(context, gamesUri), 3)
33 for (file in children) {
34 if (!file.isDirectory) {
35 // Check that the file has an extension we care about before trying to read out of it.
36 if (Game.extensions.contains(FileUtil.getExtension(file.uri))) {
37 games.add(getGame(file.uri))
38 }
39 }
40 }
41 34
42 // Cache list of games found on disk 35 // Cache list of games found on disk
43 val serializedGames = mutableSetOf<String>() 36 val serializedGames = mutableSetOf<String>()
@@ -52,6 +45,30 @@ object GameHelper {
52 return games.toList() 45 return games.toList()
53 } 46 }
54 47
48 private fun addGamesRecursive(
49 games: MutableList<Game>,
50 files: Array<MinimalDocumentFile>,
51 depth: Int
52 ) {
53 if (depth <= 0) {
54 return
55 }
56
57 files.forEach {
58 if (it.isDirectory) {
59 addGamesRecursive(
60 games,
61 FileUtil.listFiles(YuzuApplication.appContext, it.uri),
62 depth - 1
63 )
64 } else {
65 if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
66 games.add(getGame(it.uri))
67 }
68 }
69 }
70 }
71
55 private fun getGame(uri: Uri): Game { 72 private fun getGame(uri: Uri): Game {
56 val filePath = uri.toString() 73 val filePath = uri.toString()
57 var name = NativeLibrary.getTitle(filePath) 74 var name = NativeLibrary.getTitle(filePath)
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index c23b2f19e..8b99d1d6e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -30,6 +30,7 @@
30#include "core/cpu_manager.h" 30#include "core/cpu_manager.h"
31#include "core/crypto/key_manager.h" 31#include "core/crypto/key_manager.h"
32#include "core/file_sys/card_image.h" 32#include "core/file_sys/card_image.h"
33#include "core/file_sys/content_archive.h"
33#include "core/file_sys/registered_cache.h" 34#include "core/file_sys/registered_cache.h"
34#include "core/file_sys/submission_package.h" 35#include "core/file_sys/submission_package.h"
35#include "core/file_sys/vfs.h" 36#include "core/file_sys/vfs.h"
@@ -224,6 +225,42 @@ public:
224 m_system.Renderer().NotifySurfaceChanged(); 225 m_system.Renderer().NotifySurfaceChanged();
225 } 226 }
226 227
228 void ConfigureFilesystemProvider(const std::string& filepath) {
229 const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
230 if (!file) {
231 return;
232 }
233
234 auto loader = Loader::GetLoader(m_system, file);
235 if (!loader) {
236 return;
237 }
238
239 const auto file_type = loader->GetFileType();
240 if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
241 return;
242 }
243
244 u64 program_id = 0;
245 const auto res2 = loader->ReadProgramId(program_id);
246 if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
247 m_manual_provider->AddEntry(FileSys::TitleType::Application,
248 FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()),
249 program_id, file);
250 } else if (res2 == Loader::ResultStatus::Success &&
251 (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
252 const auto nsp = file_type == Loader::FileType::NSP
253 ? std::make_shared<FileSys::NSP>(file)
254 : FileSys::XCI{file}.GetSecurePartitionNSP();
255 for (const auto& title : nsp->GetNCAs()) {
256 for (const auto& entry : title.second) {
257 m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first,
258 entry.second->GetBaseFile());
259 }
260 }
261 }
262 }
263
227 Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { 264 Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
228 std::scoped_lock lock(m_mutex); 265 std::scoped_lock lock(m_mutex);
229 266
@@ -254,8 +291,14 @@ public:
254 std::move(android_keyboard), // Software Keyboard 291 std::move(android_keyboard), // Software Keyboard
255 nullptr, // Web Browser 292 nullptr, // Web Browser
256 }); 293 });
294
295 // Initialize filesystem.
296 m_manual_provider = std::make_unique<FileSys::ManualContentProvider>();
257 m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); 297 m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
298 m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
299 m_manual_provider.get());
258 m_system.GetFileSystemController().CreateFactories(*m_vfs); 300 m_system.GetFileSystemController().CreateFactories(*m_vfs);
301 ConfigureFilesystemProvider(filepath);
259 302
260 // Initialize account manager 303 // Initialize account manager
261 m_profile_manager = std::make_unique<Service::Account::ProfileManager>(); 304 m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
@@ -489,6 +532,7 @@ private:
489 bool m_is_paused{}; 532 bool m_is_paused{};
490 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; 533 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
491 std::unique_ptr<Service::Account::ProfileManager> m_profile_manager; 534 std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
535 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
492 536
493 // GPU driver parameters 537 // GPU driver parameters
494 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library; 538 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
diff --git a/src/common/swap.h b/src/common/swap.h
index 085baaf9a..fde343e45 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -460,11 +460,6 @@ S operator&(const S& i, const swap_struct_t<T, F> v) {
460 return i & v.swap(); 460 return i & v.swap();
461} 461}
462 462
463template <typename S, typename T, typename F>
464S operator&(const swap_struct_t<T, F> v, const S& i) {
465 return static_cast<S>(v.swap() & i);
466}
467
468// Comparison 463// Comparison
469template <typename S, typename T, typename F> 464template <typename S, typename T, typename F>
470bool operator<(const S& p, const swap_struct_t<T, F> v) { 465bool operator<(const S& p, const swap_struct_t<T, F> v) {
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index a28af3594..f70adab82 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -606,9 +606,9 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
606 const auto result = RemoveExistingEntry(title_id); 606 const auto result = RemoveExistingEntry(title_id);
607 607
608 // Install Metadata File 608 // Install Metadata File
609 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data); 609 const auto meta_result = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
610 if (res != InstallResult::Success) { 610 if (meta_result != InstallResult::Success) {
611 return res; 611 return meta_result;
612 } 612 }
613 613
614 // Install all the other NCAs 614 // Install all the other NCAs
@@ -621,9 +621,19 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
621 if (nca == nullptr) { 621 if (nca == nullptr) {
622 return InstallResult::ErrorCopyFailed; 622 return InstallResult::ErrorCopyFailed;
623 } 623 }
624 const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); 624 if (nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
625 if (res2 != InstallResult::Success) { 625 nca->GetTitleId() != title_id) {
626 return res2; 626 // Create fake cnmt for patch to multiprogram application
627 const auto sub_nca_result =
628 InstallEntry(*nca, TitleType::Update, overwrite_if_exists, copy);
629 if (sub_nca_result != InstallResult::Success) {
630 return sub_nca_result;
631 }
632 continue;
633 }
634 const auto nca_result = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
635 if (nca_result != InstallResult::Success) {
636 return nca_result;
627 } 637 }
628 } 638 }
629 639
@@ -663,6 +673,8 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
663} 673}
664 674
665bool RegisteredCache::RemoveExistingEntry(u64 title_id) const { 675bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
676 bool removed_data = false;
677
666 const auto delete_nca = [this](const NcaID& id) { 678 const auto delete_nca = [this](const NcaID& id) {
667 const auto path = GetRelativePathFromNcaID(id, false, true, false); 679 const auto path = GetRelativePathFromNcaID(id, false, true, false);
668 680
@@ -706,11 +718,18 @@ bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
706 const auto deleted_html = delete_nca(html_id); 718 const auto deleted_html = delete_nca(html_id);
707 const auto deleted_legal = delete_nca(legal_id); 719 const auto deleted_legal = delete_nca(legal_id);
708 720
709 return deleted_meta && (deleted_meta || deleted_program || deleted_data || 721 removed_data |= (deleted_meta || deleted_program || deleted_data || deleted_control ||
710 deleted_control || deleted_html || deleted_legal); 722 deleted_html || deleted_legal);
711 } 723 }
712 724
713 return false; 725 // If patch entries for any program exist in yuzu meta, remove them
726 for (u8 i = 0; i < 0x10; i++) {
727 const auto meta_dir = dir->CreateDirectoryRelative("yuzu_meta");
728 const auto filename = GetCNMTName(TitleType::Update, title_id + i);
729 removed_data |= meta_dir->DeleteFile(filename);
730 }
731
732 return removed_data;
714} 733}
715 734
716InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, 735InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index e573e2a57..703049ede 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -38,7 +38,7 @@ namespace {
38 */ 38 */
39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, 39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
40 KProcessAddress stack_top) { 40 KProcessAddress stack_top) {
41 const KProcessAddress entry_point = owner_process.GetPageTable().GetCodeRegionStart(); 41 const KProcessAddress entry_point = owner_process.GetEntryPoint();
42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1)); 42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
43 43
44 KThread* thread = KThread::Create(system.Kernel()); 44 KThread* thread = KThread::Create(system.Kernel());
@@ -358,6 +358,21 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
358 m_system_resource_size = metadata.GetSystemResourceSize(); 358 m_system_resource_size = metadata.GetSystemResourceSize();
359 m_image_size = code_size; 359 m_image_size = code_size;
360 360
361 if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit) {
362 // For 39-bit processes, the ASLR region starts at 0x800'0000 and is ~512GiB large.
363 // However, some (buggy) programs/libraries like skyline incorrectly depend on the
364 // existence of ASLR pages before the entry point, so we will adjust the load address
365 // to point to about 2GiB into the ASLR region.
366 m_code_address = 0x8000'0000;
367 } else {
368 // All other processes can be mapped at the beginning of the code region.
369 if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is36Bit) {
370 m_code_address = 0x800'0000;
371 } else {
372 m_code_address = 0x20'0000;
373 }
374 }
375
361 KScopedResourceReservation memory_reservation( 376 KScopedResourceReservation memory_reservation(
362 m_resource_limit, LimitableResource::PhysicalMemoryMax, code_size + m_system_resource_size); 377 m_resource_limit, LimitableResource::PhysicalMemoryMax, code_size + m_system_resource_size);
363 if (!memory_reservation.Succeeded()) { 378 if (!memory_reservation.Succeeded()) {
@@ -368,15 +383,15 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
368 // Initialize process address space 383 // Initialize process address space
369 if (const Result result{m_page_table.InitializeForProcess( 384 if (const Result result{m_page_table.InitializeForProcess(
370 metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application, 385 metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
371 0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()), m_resource_limit, 386 this->GetEntryPoint(), code_size, std::addressof(m_kernel.GetAppSystemResource()),
372 m_kernel.System().ApplicationMemory())}; 387 m_resource_limit, m_kernel.System().ApplicationMemory())};
373 result.IsError()) { 388 result.IsError()) {
374 R_RETURN(result); 389 R_RETURN(result);
375 } 390 }
376 391
377 // Map process code region 392 // Map process code region
378 if (const Result result{m_page_table.MapProcessCode(m_page_table.GetCodeRegionStart(), 393 if (const Result result{m_page_table.MapProcessCode(this->GetEntryPoint(), code_size / PageSize,
379 code_size / PageSize, KMemoryState::Code, 394 KMemoryState::Code,
380 KMemoryPermission::None)}; 395 KMemoryPermission::None)};
381 result.IsError()) { 396 result.IsError()) {
382 R_RETURN(result); 397 R_RETURN(result);
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index c9b37e138..4fdeaf11a 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -177,6 +177,10 @@ public:
177 return m_program_id; 177 return m_program_id;
178 } 178 }
179 179
180 KProcessAddress GetEntryPoint() const {
181 return m_code_address;
182 }
183
180 /// Gets the resource limit descriptor for this process 184 /// Gets the resource limit descriptor for this process
181 KResourceLimit* GetResourceLimit() const; 185 KResourceLimit* GetResourceLimit() const;
182 186
@@ -485,6 +489,9 @@ private:
485 /// Address indicating the location of the process' dedicated TLS region. 489 /// Address indicating the location of the process' dedicated TLS region.
486 KProcessAddress m_plr_address = 0; 490 KProcessAddress m_plr_address = 0;
487 491
492 /// Address indicating the location of the process's entry point.
493 KProcessAddress m_code_address = 0;
494
488 /// Random values for svcGetInfo RandomEntropy 495 /// Random values for svcGetInfo RandomEntropy
489 std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{}; 496 std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{};
490 497
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 4c1ea1a5b..508db7360 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -4,6 +4,7 @@
4#include <utility> 4#include <utility>
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/fs/fs.h"
7#include "common/fs/path_util.h" 8#include "common/fs/path_util.h"
8#include "common/settings.h" 9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
@@ -154,10 +155,18 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
154 std::string src_path(Common::FS::SanitizePath(src_path_)); 155 std::string src_path(Common::FS::SanitizePath(src_path_));
155 std::string dest_path(Common::FS::SanitizePath(dest_path_)); 156 std::string dest_path(Common::FS::SanitizePath(dest_path_));
156 auto src = backing->GetFileRelative(src_path); 157 auto src = backing->GetFileRelative(src_path);
158 auto dst = backing->GetFileRelative(dest_path);
157 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { 159 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
158 // Use more-optimized vfs implementation rename. 160 // Use more-optimized vfs implementation rename.
159 if (src == nullptr) 161 if (src == nullptr) {
160 return FileSys::ERROR_PATH_NOT_FOUND; 162 return FileSys::ERROR_PATH_NOT_FOUND;
163 }
164
165 if (dst && Common::FS::Exists(dst->GetFullPath())) {
166 LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
167 return FileSys::ERROR_PATH_ALREADY_EXISTS;
168 }
169
161 if (!src->Rename(Common::FS::GetFilename(dest_path))) { 170 if (!src->Rename(Common::FS::GetFilename(dest_path))) {
162 // TODO(DarkLordZach): Find a better error code for this 171 // TODO(DarkLordZach): Find a better error code for this
163 return ResultUnknown; 172 return ResultUnknown;
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 07e570a9f..7d7bb8687 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -204,9 +204,11 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
204 if (!mapping->fixed) { 204 if (!mapping->fixed) {
205 auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; 205 auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
206 u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; 206 u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
207 u32 page_size{mapping->big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
208 u64 aligned_size{Common::AlignUp(mapping->size, page_size)};
207 209
208 allocator.Free(static_cast<u32>(mapping->offset >> page_size_bits), 210 allocator.Free(static_cast<u32>(mapping->offset >> page_size_bits),
209 static_cast<u32>(mapping->size >> page_size_bits)); 211 static_cast<u32>(aligned_size >> page_size_bits));
210 } 212 }
211 213
212 // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state 214 // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 45b2c43b7..d539ed0f4 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -79,8 +79,8 @@ protected:
79 using HandlerFnP = void (Self::*)(HLERequestContext&); 79 using HandlerFnP = void (Self::*)(HLERequestContext&);
80 80
81 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. 81 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
82 [[nodiscard]] std::scoped_lock<std::mutex> LockService() { 82 [[nodiscard]] virtual std::unique_lock<std::mutex> LockService() {
83 return std::scoped_lock{lock_service}; 83 return std::unique_lock{lock_service};
84 } 84 }
85 85
86 /// System context that the service operates under. 86 /// System context that the service operates under.
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 11f8efbac..d8509c1dd 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -1029,6 +1029,11 @@ BSD::~BSD() {
1029 } 1029 }
1030} 1030}
1031 1031
1032std::unique_lock<std::mutex> BSD::LockService() {
1033 // Do not lock socket IClient instances.
1034 return {};
1035}
1036
1032BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { 1037BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
1033 // clang-format off 1038 // clang-format off
1034 static const FunctionInfo functions[] = { 1039 static const FunctionInfo functions[] = {
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 430edb97c..161f22b9b 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -186,6 +186,9 @@ private:
186 186
187 // Callback identifier for the OnProxyPacketReceived event. 187 // Callback identifier for the OnProxyPacketReceived event.
188 Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received; 188 Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
189
190protected:
191 virtual std::unique_lock<std::mutex> LockService() override;
189}; 192};
190 193
191class BSDCFG final : public ServiceFramework<BSDCFG> { 194class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 2cba9e5c9..6c8427b0d 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -139,7 +139,6 @@ private:
139 bool do_not_close_socket = false; 139 bool do_not_close_socket = false;
140 bool get_server_cert_chain = false; 140 bool get_server_cert_chain = false;
141 std::shared_ptr<Network::SocketBase> socket; 141 std::shared_ptr<Network::SocketBase> socket;
142 bool did_set_host_name = false;
143 bool did_handshake = false; 142 bool did_handshake = false;
144 143
145 Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) { 144 Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
@@ -174,11 +173,7 @@ private:
174 Result SetHostNameImpl(const std::string& hostname) { 173 Result SetHostNameImpl(const std::string& hostname) {
175 LOG_DEBUG(Service_SSL, "called. hostname={}", hostname); 174 LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
176 ASSERT(!did_handshake); 175 ASSERT(!did_handshake);
177 Result res = backend->SetHostName(hostname); 176 return backend->SetHostName(hostname);
178 if (res == ResultSuccess) {
179 did_set_host_name = true;
180 }
181 return res;
182 } 177 }
183 178
184 Result SetVerifyOptionImpl(u32 option) { 179 Result SetVerifyOptionImpl(u32 option) {
@@ -208,9 +203,6 @@ private:
208 203
209 Result DoHandshakeImpl() { 204 Result DoHandshakeImpl() {
210 ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; }); 205 ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
211 ASSERT_OR_EXECUTE_MSG(
212 did_set_host_name, { return ResultInternalError; },
213 "Expected SetHostName before DoHandshake");
214 Result res = backend->DoHandshake(); 206 Result res = backend->DoHandshake();
215 did_handshake = res.IsSuccess(); 207 did_handshake = res.IsSuccess();
216 return res; 208 return res;
diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp
index b2dd37cd4..5714e6f3c 100644
--- a/src/core/hle/service/ssl/ssl_backend_openssl.cpp
+++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp
@@ -167,9 +167,8 @@ public:
167 } 167 }
168 168
169 ~SSLConnectionBackendOpenSSL() { 169 ~SSLConnectionBackendOpenSSL() {
170 // these are null-tolerant: 170 // this is null-tolerant:
171 SSL_free(ssl); 171 SSL_free(ssl);
172 BIO_free(bio);
173 } 172 }
174 173
175 static void KeyLogCallback(const SSL* ssl, const char* line) { 174 static void KeyLogCallback(const SSL* ssl, const char* line) {
diff --git a/src/core/hle/service/ssl/ssl_backend_schannel.cpp b/src/core/hle/service/ssl/ssl_backend_schannel.cpp
index bda12b761..d834a0c1f 100644
--- a/src/core/hle/service/ssl/ssl_backend_schannel.cpp
+++ b/src/core/hle/service/ssl/ssl_backend_schannel.cpp
@@ -31,9 +31,9 @@ CredHandle cred_handle;
31static void OneTimeInit() { 31static void OneTimeInit() {
32 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; 32 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
33 schannel_cred.dwFlags = 33 schannel_cred.dwFlags =
34 SCH_USE_STRONG_CRYPTO | // don't allow insecure protocols 34 SCH_USE_STRONG_CRYPTO | // don't allow insecure protocols
35 SCH_CRED_AUTO_CRED_VALIDATION | // validate certs 35 SCH_CRED_NO_SERVERNAME_CHECK | // don't validate server names
36 SCH_CRED_NO_DEFAULT_CREDS; // don't automatically present a client certificate 36 SCH_CRED_NO_DEFAULT_CREDS; // don't automatically present a client certificate
37 // ^ I'm assuming that nobody would want to connect Yuzu to a 37 // ^ I'm assuming that nobody would want to connect Yuzu to a
38 // service that requires some OS-provided corporate client 38 // service that requires some OS-provided corporate client
39 // certificate, and presenting one to some arbitrary server 39 // certificate, and presenting one to some arbitrary server
@@ -227,16 +227,15 @@ public:
227 ciphertext_read_buf.size()); 227 ciphertext_read_buf.size());
228 } 228 }
229 229
230 const SECURITY_STATUS ret = 230 char* hostname_ptr = hostname ? const_cast<char*>(hostname->c_str()) : nullptr;
231 InitializeSecurityContextA(&cred_handle, initial_call_done ? &ctxt : nullptr, 231 const SECURITY_STATUS ret = InitializeSecurityContextA(
232 // Caller ensured we have set a hostname: 232 &cred_handle, initial_call_done ? &ctxt : nullptr, hostname_ptr, req,
233 const_cast<char*>(hostname.value().c_str()), req, 233 0, // Reserved1
234 0, // Reserved1 234 0, // TargetDataRep not used with Schannel
235 0, // TargetDataRep not used with Schannel 235 initial_call_done ? &input_desc : nullptr,
236 initial_call_done ? &input_desc : nullptr, 236 0, // Reserved2
237 0, // Reserved2 237 initial_call_done ? nullptr : &ctxt, &output_desc, &attr,
238 initial_call_done ? nullptr : &ctxt, &output_desc, &attr, 238 nullptr); // ptsExpiry
239 nullptr); // ptsExpiry
240 239
241 if (output_buffers[0].pvBuffer) { 240 if (output_buffers[0].pvBuffer) {
242 const std::span span(static_cast<u8*>(output_buffers[0].pvBuffer), 241 const std::span span(static_cast<u8*>(output_buffers[0].pvBuffer),
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index e04ad19db..f4eaf3331 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -153,7 +153,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
153 153
154 // Load NSO modules 154 // Load NSO modules
155 modules.clear(); 155 modules.clear();
156 const VAddr base_address{GetInteger(process.GetPageTable().GetCodeRegionStart())}; 156 const VAddr base_address{GetInteger(process.GetEntryPoint())};
157 VAddr next_load_addr{base_address}; 157 VAddr next_load_addr{base_address};
158 const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), 158 const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
159 system.GetContentProvider()}; 159 system.GetContentProvider()};
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index ffe976b94..d722459c6 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -96,7 +96,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
96 } 96 }
97 97
98 codeset.memory = std::move(program_image); 98 codeset.memory = std::move(program_image);
99 const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart()); 99 const VAddr base_address = GetInteger(process.GetEntryPoint());
100 process.LoadModule(std::move(codeset), base_address); 100 process.LoadModule(std::move(codeset), base_address);
101 101
102 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); 102 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 506808b5d..d7562b4bc 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -203,7 +203,7 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
203 203
204 // Load codeset for current process 204 // Load codeset for current process
205 codeset.memory = std::move(program_image); 205 codeset.memory = std::move(program_image);
206 process.LoadModule(std::move(codeset), process.GetPageTable().GetCodeRegionStart()); 206 process.LoadModule(std::move(codeset), process.GetEntryPoint());
207 207
208 return true; 208 return true;
209} 209}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 74cc9579f..549822506 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -167,7 +167,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
167 modules.clear(); 167 modules.clear();
168 168
169 // Load module 169 // Load module
170 const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart()); 170 const VAddr base_address = GetInteger(process.GetEntryPoint());
171 if (!LoadModule(process, system, *file, base_address, true, true)) { 171 if (!LoadModule(process, system, *file, base_address, true, true)) {
172 return {ResultStatus::ErrorLoadingNSO, {}}; 172 return {ResultStatus::ErrorLoadingNSO, {}};
173 } 173 }
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index b5b3e7eda..ed875d444 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -117,8 +117,8 @@ json GetProcessorStateDataAuto(Core::System& system) {
117 arm.SaveContext(context); 117 arm.SaveContext(context);
118 118
119 return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", 119 return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32",
120 GetInteger(process->GetPageTable().GetCodeRegionStart()), 120 GetInteger(process->GetEntryPoint()), context.sp, context.pc,
121 context.sp, context.pc, context.pstate, context.cpu_registers); 121 context.pstate, context.cpu_registers);
122} 122}
123 123
124json GetBacktraceData(Core::System& system) { 124json GetBacktraceData(Core::System& system) {
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 870e76ab0..188e862d7 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -835,15 +835,15 @@ public:
835 return input_engine->SupportsNfc(identifier); 835 return input_engine->SupportsNfc(identifier);
836 } 836 }
837 837
838 Common::Input::NfcState StartNfcPolling() { 838 Common::Input::NfcState StartNfcPolling() override {
839 return input_engine->StartNfcPolling(identifier); 839 return input_engine->StartNfcPolling(identifier);
840 } 840 }
841 841
842 Common::Input::NfcState StopNfcPolling() { 842 Common::Input::NfcState StopNfcPolling() override {
843 return input_engine->StopNfcPolling(identifier); 843 return input_engine->StopNfcPolling(identifier);
844 } 844 }
845 845
846 Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) { 846 Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) override {
847 return input_engine->ReadAmiiboData(identifier, out_data); 847 return input_engine->ReadAmiiboData(identifier, out_data);
848 } 848 }
849 849
@@ -852,11 +852,11 @@ public:
852 } 852 }
853 853
854 Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, 854 Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request,
855 Common::Input::MifareRequest& out_data) { 855 Common::Input::MifareRequest& out_data) override {
856 return input_engine->ReadMifareData(identifier, request, out_data); 856 return input_engine->ReadMifareData(identifier, request, out_data);
857 } 857 }
858 858
859 Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { 859 Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) override {
860 return input_engine->WriteMifareData(identifier, request); 860 return input_engine->WriteMifareData(identifier, request);
861 } 861 }
862 862
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp
index 905505ca1..5d0bb9cc4 100644
--- a/src/video_core/macro/macro.cpp
+++ b/src/video_core/macro/macro.cpp
@@ -27,14 +27,24 @@ MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192))
27 27
28namespace Tegra { 28namespace Tegra {
29 29
30static void Dump(u64 hash, std::span<const u32> code) { 30static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
31 const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)}; 31 const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
32 const auto macro_dir{base_dir / "macros"}; 32 const auto macro_dir{base_dir / "macros"};
33 if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) { 33 if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
34 LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories"); 34 LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
35 return; 35 return;
36 } 36 }
37 const auto name{macro_dir / fmt::format("{:016x}.macro", hash)}; 37 auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
38
39 if (decompiled) {
40 auto new_name{macro_dir / fmt::format("decompiled_{:016x}.macro", hash)};
41 if (Common::FS::Exists(name)) {
42 (void)Common::FS::RenameFile(name, new_name);
43 return;
44 }
45 name = new_name;
46 }
47
38 std::fstream macro_file(name, std::ios::out | std::ios::binary); 48 std::fstream macro_file(name, std::ios::out | std::ios::binary);
39 if (!macro_file) { 49 if (!macro_file) {
40 LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}", 50 LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}",
@@ -90,9 +100,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
90 if (!mid_method.has_value()) { 100 if (!mid_method.has_value()) {
91 cache_info.lle_program = Compile(macro_code->second); 101 cache_info.lle_program = Compile(macro_code->second);
92 cache_info.hash = Common::HashValue(macro_code->second); 102 cache_info.hash = Common::HashValue(macro_code->second);
93 if (Settings::values.dump_macros) {
94 Dump(cache_info.hash, macro_code->second);
95 }
96 } else { 103 } else {
97 const auto& macro_cached = uploaded_macro_code[mid_method.value()]; 104 const auto& macro_cached = uploaded_macro_code[mid_method.value()];
98 const auto rebased_method = method - mid_method.value(); 105 const auto rebased_method = method - mid_method.value();
@@ -102,9 +109,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
102 code.size() * sizeof(u32)); 109 code.size() * sizeof(u32));
103 cache_info.hash = Common::HashValue(code); 110 cache_info.hash = Common::HashValue(code);
104 cache_info.lle_program = Compile(code); 111 cache_info.lle_program = Compile(code);
105 if (Settings::values.dump_macros) {
106 Dump(cache_info.hash, code);
107 }
108 } 112 }
109 113
110 auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); 114 auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
@@ -117,6 +121,10 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
117 MICROPROFILE_SCOPE(MacroHLE); 121 MICROPROFILE_SCOPE(MacroHLE);
118 cache_info.hle_program->Execute(parameters, method); 122 cache_info.hle_program->Execute(parameters, method);
119 } 123 }
124
125 if (Settings::values.dump_macros) {
126 Dump(cache_info.hash, macro_code->second, cache_info.has_hle_program);
127 }
120 } 128 }
121} 129}
122 130
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index c1314ca99..fe432dfe1 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -611,9 +611,6 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
611 611
612 const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; 612 const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
613 Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); 613 Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
614 if (Settings::values.dump_shaders) {
615 env.Dump(hash, key.unique_hashes[index]);
616 }
617 if (!uses_vertex_a || index != 1) { 614 if (!uses_vertex_a || index != 1) {
618 // Normal path 615 // Normal path
619 programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); 616 programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
@@ -624,6 +621,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
624 programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); 621 programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
625 } 622 }
626 623
624 if (Settings::values.dump_shaders) {
625 env.Dump(hash, key.unique_hashes[index]);
626 }
627
627 if (programs[index].info.requires_layer_emulation) { 628 if (programs[index].info.requires_layer_emulation) {
628 layer_source_program = &programs[index]; 629 layer_source_program = &programs[index];
629 } 630 }
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index 72aedb8d8..bc16145be 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -41,9 +41,6 @@ namespace {
41 bool enable_validation) { 41 bool enable_validation) {
42 std::vector<const char*> extensions; 42 std::vector<const char*> extensions;
43 extensions.reserve(6); 43 extensions.reserve(6);
44#ifdef __APPLE__
45 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
46#endif
47 switch (window_type) { 44 switch (window_type) {
48 case Core::Frontend::WindowSystemType::Headless: 45 case Core::Frontend::WindowSystemType::Headless:
49 break; 46 break;
@@ -74,6 +71,11 @@ namespace {
74 if (window_type != Core::Frontend::WindowSystemType::Headless) { 71 if (window_type != Core::Frontend::WindowSystemType::Headless) {
75 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 72 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
76 } 73 }
74#ifdef __APPLE__
75 if (AreExtensionsSupported(dld, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME})) {
76 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
77 }
78#endif
77 if (enable_validation) { 79 if (enable_validation) {
78 const bool debug_utils = 80 const bool debug_utils =
79 AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); 81 AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp
index 47f6f2a03..0130f6a0d 100644
--- a/src/video_core/vulkan_common/vulkan_library.cpp
+++ b/src/video_core/vulkan_common/vulkan_library.cpp
@@ -19,13 +19,17 @@ std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
19#else 19#else
20 auto library = std::make_shared<Common::DynamicLibrary>(); 20 auto library = std::make_shared<Common::DynamicLibrary>();
21#ifdef __APPLE__ 21#ifdef __APPLE__
22 const auto libvulkan_filename =
23 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.1.dylib";
24 const auto libmoltenvk_filename =
25 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libMoltenVK.dylib";
26 const char* library_paths[] = {std::getenv("LIBVULKAN_PATH"), libvulkan_filename.c_str(),
27 libmoltenvk_filename.c_str()};
22 // Check if a path to a specific Vulkan library has been specified. 28 // Check if a path to a specific Vulkan library has been specified.
23 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH"); 29 for (const auto& library_path : library_paths) {
24 if (!libvulkan_env || !library->Open(libvulkan_env)) { 30 if (library_path && library->Open(library_path)) {
25 // Use the libvulkan.dylib from the application bundle. 31 break;
26 const auto filename = 32 }
27 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
28 void(library->Open(Common::FS::PathToUTF8String(filename).c_str()));
29 } 33 }
30#else 34#else
31 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); 35 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
diff --git a/src/web_service/verify_user_jwt.cpp b/src/web_service/verify_user_jwt.cpp
index 129eb1968..f88f67620 100644
--- a/src/web_service/verify_user_jwt.cpp
+++ b/src/web_service/verify_user_jwt.cpp
@@ -4,6 +4,7 @@
4#if defined(__GNUC__) || defined(__clang__) 4#if defined(__GNUC__) || defined(__clang__)
5#pragma GCC diagnostic push 5#pragma GCC diagnostic push
6#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" 6#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
7#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // for deprecated OpenSSL functions
7#endif 8#endif
8#include <jwt/jwt.hpp> 9#include <jwt/jwt.hpp>
9#if defined(__GNUC__) || defined(__clang__) 10#if defined(__GNUC__) || defined(__clang__)
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 2e4da696c..8f86a1553 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -313,6 +313,18 @@ if (APPLE)
313 target_sources(yuzu PRIVATE ${MACOSX_ICON}) 313 target_sources(yuzu PRIVATE ${MACOSX_ICON})
314 set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE) 314 set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
315 set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) 315 set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
316
317 if (NOT USE_SYSTEM_MOLTENVK)
318 set(MOLTENVK_PLATFORM "macOS")
319 set(MOLTENVK_VERSION "v1.2.5")
320 download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
321 endif()
322 find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
323 message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
324 set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks
325 XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
326 target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
327
316elseif(WIN32) 328elseif(WIN32)
317 # compile as a win32 gui application instead of a console application 329 # compile as a win32 gui application instead of a console application
318 if (QT_VERSION VERSION_GREATER_EQUAL 6) 330 if (QT_VERSION VERSION_GREATER_EQUAL 6)
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp
index bdb38c8ea..4e45bc844 100644
--- a/src/yuzu/configuration/shared_widget.cpp
+++ b/src/yuzu/configuration/shared_widget.cpp
@@ -235,6 +235,7 @@ QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& gi
235 slider->setValue(std::stoi(setting.ToString())); 235 slider->setValue(std::stoi(setting.ToString()));
236 236
237 slider->setInvertedAppearance(reversed); 237 slider->setInvertedAppearance(reversed);
238 slider->setInvertedControls(reversed);
238 239
239 serializer = [this]() { return std::to_string(slider->value()); }; 240 serializer = [this]() { return std::to_string(slider->value()); };
240 restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); }; 241 restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); };
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 9404365b4..e7fb8a282 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -191,8 +191,9 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
191} 191}
192 192
193QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name, 193QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
194 const std::vector<u8>& icon, Loader::AppLoader& loader, 194 const std::size_t size, const std::vector<u8>& icon,
195 u64 program_id, const CompatibilityList& compatibility_list, 195 Loader::AppLoader& loader, u64 program_id,
196 const CompatibilityList& compatibility_list,
196 const FileSys::PatchManager& patch) { 197 const FileSys::PatchManager& patch) {
197 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 198 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
198 199
@@ -210,7 +211,7 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
210 file_type_string, program_id), 211 file_type_string, program_id),
211 new GameListItemCompat(compatibility), 212 new GameListItemCompat(compatibility),
212 new GameListItem(file_type_string), 213 new GameListItem(file_type_string),
213 new GameListItemSize(Common::FS::GetSize(path)), 214 new GameListItemSize(size),
214 }; 215 };
215 216
216 const auto patch_versions = GetGameListCachedObject( 217 const auto patch_versions = GetGameListCachedObject(
@@ -278,8 +279,8 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
278 GetMetadataFromControlNCA(patch, *control, icon, name); 279 GetMetadataFromControlNCA(patch, *control, icon, name);
279 } 280 }
280 281
281 emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id, 282 emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader,
282 compatibility_list, patch), 283 program_id, compatibility_list, patch),
283 parent_dir); 284 parent_dir);
284 } 285 }
285} 286}
@@ -354,8 +355,9 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
354 const FileSys::PatchManager patch{id, system.GetFileSystemController(), 355 const FileSys::PatchManager patch{id, system.GetFileSystemController(),
355 system.GetContentProvider()}; 356 system.GetContentProvider()};
356 357
357 emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, id, 358 emit EntryReady(MakeGameListEntry(physical_name, name,
358 compatibility_list, patch), 359 Common::FS::GetSize(physical_name), icon,
360 *loader, id, compatibility_list, patch),
359 parent_dir); 361 parent_dir);
360 } 362 }
361 } else { 363 } else {
@@ -368,9 +370,10 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
368 const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), 370 const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
369 system.GetContentProvider()}; 371 system.GetContentProvider()};
370 372
371 emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, 373 emit EntryReady(
372 program_id, compatibility_list, patch), 374 MakeGameListEntry(physical_name, name, Common::FS::GetSize(physical_name),
373 parent_dir); 375 icon, *loader, program_id, compatibility_list, patch),
376 parent_dir);
374 } 377 }
375 } 378 }
376 } else if (is_dir) { 379 } else if (is_dir) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a9d035f3d..8e933af64 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1811,6 +1811,43 @@ bool GMainWindow::SelectAndSetCurrentUser(
1811 return true; 1811 return true;
1812} 1812}
1813 1813
1814void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
1815 // Ensure all NCAs are registered before launching the game
1816 const auto file = vfs->OpenFile(filepath, FileSys::Mode::Read);
1817 if (!file) {
1818 return;
1819 }
1820
1821 auto loader = Loader::GetLoader(*system, file);
1822 if (!loader) {
1823 return;
1824 }
1825
1826 const auto file_type = loader->GetFileType();
1827 if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
1828 return;
1829 }
1830
1831 u64 program_id = 0;
1832 const auto res2 = loader->ReadProgramId(program_id);
1833 if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
1834 provider->AddEntry(FileSys::TitleType::Application,
1835 FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id,
1836 file);
1837 } else if (res2 == Loader::ResultStatus::Success &&
1838 (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
1839 const auto nsp = file_type == Loader::FileType::NSP
1840 ? std::make_shared<FileSys::NSP>(file)
1841 : FileSys::XCI{file}.GetSecurePartitionNSP();
1842 for (const auto& title : nsp->GetNCAs()) {
1843 for (const auto& entry : title.second) {
1844 provider->AddEntry(entry.first.first, entry.first.second, title.first,
1845 entry.second->GetBaseFile());
1846 }
1847 }
1848 }
1849}
1850
1814void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, 1851void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index,
1815 StartGameType type) { 1852 StartGameType type) {
1816 LOG_INFO(Frontend, "yuzu starting..."); 1853 LOG_INFO(Frontend, "yuzu starting...");
@@ -1825,6 +1862,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1825 1862
1826 last_filename_booted = filename; 1863 last_filename_booted = filename;
1827 1864
1865 ConfigureFilesystemProvider(filename.toStdString());
1828 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); 1866 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
1829 const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index); 1867 const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index);
1830 1868
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 2cfb96257..1b7055122 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -399,6 +399,7 @@ private:
399 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); 399 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
400 bool CheckDarkMode(); 400 bool CheckDarkMode();
401 bool CheckSystemArchiveDecryption(); 401 bool CheckSystemArchiveDecryption();
402 void ConfigureFilesystemProvider(const std::string& filepath);
402 403
403 QString GetTasStateDescription() const; 404 QString GetTasStateDescription() const;
404 bool CreateShortcut(const std::string& shortcut_path, const std::string& title, 405 bool CreateShortcut(const std::string& shortcut_path, const std::string& title,