Compare commits

...

5 Commits

Author SHA1 Message Date
712d7604cd Android 210 2024-01-25 19:25:22 +00:00
5994e45f3f Merge yuzu-emu#12777 2024-01-25 19:25:22 +00:00
7701c91e79 Merge yuzu-emu#12769 2024-01-25 19:25:22 +00:00
2a00de23e8 Merge yuzu-emu#12759 2024-01-25 19:25:22 +00:00
3e5078f409 Merge yuzu-emu#12749 2024-01-25 19:25:22 +00:00
28 changed files with 343 additions and 206 deletions

View File

@ -1,3 +1,15 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`e3171486d`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12759](https://github.com/yuzu-emu/yuzu-android//pull/12759) | [`a120f8ff4`](https://github.com/yuzu-emu/yuzu-android//pull/12759/files) | core: miscellaneous fixes | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12769](https://github.com/yuzu-emu/yuzu-android//pull/12769) | [`ad4622da2`](https://github.com/yuzu-emu/yuzu-android//pull/12769/files) | core: hid: Reduce controller requests | [german77](https://github.com/german77/) | Yes |
| [12777](https://github.com/yuzu-emu/yuzu-android//pull/12777) | [`b8be8dff6`](https://github.com/yuzu-emu/yuzu-android//pull/12777/files) | android: Add key warning | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!-- <!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -619,6 +619,11 @@ object NativeLibrary {
*/ */
external fun clearFilesystemProvider() external fun clearFilesystemProvider()
/**
* Checks if all necessary keys are present for decryption
*/
external fun areKeysPresent(): Boolean
/** /**
* Button type for use in onTouchEvent * Button type for use in onTouchEvent
*/ */

View File

@ -26,9 +26,15 @@ class MessageDialogFragment : DialogFragment() {
val descriptionId = requireArguments().getInt(DESCRIPTION_ID) val descriptionId = requireArguments().getInt(DESCRIPTION_ID)
val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!! val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!!
val helpLinkId = requireArguments().getInt(HELP_LINK) val helpLinkId = requireArguments().getInt(HELP_LINK)
val dismissible = requireArguments().getBoolean(DISMISSIBLE)
val clearPositiveAction = requireArguments().getBoolean(CLEAR_POSITIVE_ACTION)
val builder = MaterialAlertDialogBuilder(requireContext()) val builder = MaterialAlertDialogBuilder(requireContext())
if (clearPositiveAction) {
messageDialogViewModel.positiveAction = null
}
if (messageDialogViewModel.positiveAction == null) { if (messageDialogViewModel.positiveAction == null) {
builder.setPositiveButton(R.string.close, null) builder.setPositiveButton(R.string.close, null)
} else { } else {
@ -51,6 +57,8 @@ class MessageDialogFragment : DialogFragment() {
} }
} }
isCancelable = dismissible
return builder.show() return builder.show()
} }
@ -67,6 +75,8 @@ class MessageDialogFragment : DialogFragment() {
private const val DESCRIPTION_ID = "DescriptionId" private const val DESCRIPTION_ID = "DescriptionId"
private const val DESCRIPTION_STRING = "DescriptionString" private const val DESCRIPTION_STRING = "DescriptionString"
private const val HELP_LINK = "Link" private const val HELP_LINK = "Link"
private const val DISMISSIBLE = "Dismissible"
private const val CLEAR_POSITIVE_ACTION = "ClearPositiveAction"
fun newInstance( fun newInstance(
activity: FragmentActivity? = null, activity: FragmentActivity? = null,
@ -75,22 +85,28 @@ class MessageDialogFragment : DialogFragment() {
descriptionId: Int = 0, descriptionId: Int = 0,
descriptionString: String = "", descriptionString: String = "",
helpLinkId: Int = 0, helpLinkId: Int = 0,
dismissible: Boolean = true,
positiveAction: (() -> Unit)? = null positiveAction: (() -> Unit)? = null
): MessageDialogFragment { ): MessageDialogFragment {
val dialog = MessageDialogFragment() var clearPositiveAction = false
val bundle = Bundle()
bundle.apply {
putInt(TITLE_ID, titleId)
putString(TITLE_STRING, titleString)
putInt(DESCRIPTION_ID, descriptionId)
putString(DESCRIPTION_STRING, descriptionString)
putInt(HELP_LINK, helpLinkId)
}
if (activity != null) { if (activity != null) {
ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply { ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
clear() clear()
this.positiveAction = positiveAction this.positiveAction = positiveAction
} }
} else {
clearPositiveAction = true
}
val dialog = MessageDialogFragment()
val bundle = Bundle().apply {
putInt(TITLE_ID, titleId)
putString(TITLE_STRING, titleString)
putInt(DESCRIPTION_ID, descriptionId)
putString(DESCRIPTION_STRING, descriptionString)
putInt(HELP_LINK, helpLinkId)
putBoolean(DISMISSIBLE, dismissible)
putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction)
} }
dialog.arguments = bundle dialog.arguments = bundle
return dialog return dialog

View File

@ -31,6 +31,7 @@ import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.google.android.material.transition.MaterialFadeThrough import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.NativeLibrary
import java.io.File import java.io.File
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
@ -162,7 +163,7 @@ class SetupFragment : Fragment() {
R.string.install_prod_keys_warning_help, R.string.install_prod_keys_warning_help,
{ {
val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys") val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
if (file.exists()) { if (file.exists() && NativeLibrary.areKeysPresent()) {
StepState.COMPLETE StepState.COMPLETE
} else { } else {
StepState.INCOMPLETE StepState.INCOMPLETE
@ -347,7 +348,8 @@ class SetupFragment : Fragment() {
val getProdKey = val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) { if (result != null) {
if (mainActivity.processKey(result)) { mainActivity.processKey(result)
if (NativeLibrary.areKeysPresent()) {
keyCallback.onStepCompleted() keyCallback.onStepCompleted()
} }
} }

View File

@ -31,6 +31,9 @@ class HomeViewModel : ViewModel() {
private val _reloadPropertiesList = MutableStateFlow(false) private val _reloadPropertiesList = MutableStateFlow(false)
val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow() val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow()
private val _checkKeys = MutableStateFlow(false)
val checkKeys = _checkKeys.asStateFlow()
var navigatedToSetup = false var navigatedToSetup = false
fun setNavigationVisibility(visible: Boolean, animated: Boolean) { fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
@ -66,4 +69,8 @@ class HomeViewModel : ViewModel() {
fun reloadPropertiesList(reload: Boolean) { fun reloadPropertiesList(reload: Boolean) {
_reloadPropertiesList.value = reload _reloadPropertiesList.value = reload
} }
fun setCheckKeys(value: Boolean) {
_checkKeys.value = value
}
} }

View File

@ -64,6 +64,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
override var themeId: Int = 0 override var themeId: Int = 0
private val CHECKED_DECRYPTION = "CheckedDecryption"
private var checkedDecryption = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen() val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
@ -75,6 +78,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
if (savedInstanceState != null) {
checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION)
}
if (!checkedDecryption) {
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
if (!firstTimeSetup) {
checkKeys()
}
checkedDecryption = true
}
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
@ -150,6 +165,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
} }
} }
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.checkKeys.collect {
if (it) {
checkKeys()
homeViewModel.setCheckKeys(false)
}
}
}
}
} }
// Dismiss previous notifications (should not happen unless a crash occurred) // Dismiss previous notifications (should not happen unless a crash occurred)
@ -158,6 +183,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
setInsets() setInsets()
} }
private fun checkKeys() {
if (!NativeLibrary.areKeysPresent()) {
MessageDialogFragment.newInstance(
titleId = R.string.keys_missing,
descriptionId = R.string.keys_missing_description,
helpLinkId = R.string.keys_missing_help
).show(supportFragmentManager, MessageDialogFragment.TAG)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
}
fun finishSetup(navController: NavController) { fun finishSetup(navController: NavController) {
navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment) navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment)
(binding.navigationView as NavigationBarView).setupWithNavController(navController) (binding.navigationView as NavigationBarView).setupWithNavController(navController)
@ -349,6 +389,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
R.string.install_keys_success, R.string.install_keys_success,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
homeViewModel.setCheckKeys(true)
gamesViewModel.reloadGames(true) gamesViewModel.reloadGames(true)
return true return true
} else { } else {
@ -399,6 +440,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
firmwarePath.deleteRecursively() firmwarePath.deleteRecursively()
cacheFirmwareDir.copyRecursively(firmwarePath, true) cacheFirmwareDir.copyRecursively(firmwarePath, true)
NativeLibrary.initializeSystem(true) NativeLibrary.initializeSystem(true)
homeViewModel.setCheckKeys(true)
getString(R.string.save_file_imported_success) getString(R.string.save_file_imported_success)
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -464,8 +464,8 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
}; };
return static_cast<int>( return static_cast<int>(
ContentManager::InstallNSP(&EmulationSession::GetInstance().System(), ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
EmulationSession::GetInstance().System().GetFilesystem().get(), *EmulationSession::GetInstance().System().GetFilesystem(),
GetJString(env, j_file), callback)); GetJString(env, j_file), callback));
} }
@ -825,7 +825,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject job
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj, void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id); ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId, void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
@ -835,7 +835,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
program_id, GetJString(env, jname)); program_id, GetJString(env, jname));
} }
jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobject jobj, jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
jobject jobj,
jobject jcallback) { jobject jcallback) {
auto jlambdaClass = env->GetObjectClass(jcallback); auto jlambdaClass = env->GetObjectClass(jcallback);
auto jlambdaInvokeMethod = env->GetMethodID( auto jlambdaInvokeMethod = env->GetMethodID(
@ -848,7 +849,7 @@ jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* en
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
std::vector<std::string> result = ContentManager::VerifyInstalledContents( std::vector<std::string> result = ContentManager::VerifyInstalledContents(
&session.System(), session.GetContentProvider(), callback); session.System(), *session.GetContentProvider(), callback);
jobjectArray jresult = jobjectArray jresult =
env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, "")); env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
for (size_t i = 0; i < result.size(); ++i) { for (size_t i = 0; i < result.size(); ++i) {
@ -869,7 +870,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
}; };
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
return static_cast<jint>( return static_cast<jint>(
ContentManager::VerifyGameContents(&session.System(), GetJString(env, jpath), callback)); ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback));
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
@ -918,4 +919,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env,
EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
} }
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) {
auto& system = EmulationSession::GetInstance().System();
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
return ContentManager::AreKeysPresent();
}
} // extern "C" } // extern "C"

View File

@ -144,6 +144,9 @@
<string name="no_save_data_found">No save data found</string> <string name="no_save_data_found">No save data found</string>
<string name="verify_installed_content">Verify installed content</string> <string name="verify_installed_content">Verify installed content</string>
<string name="verify_installed_content_description">Checks all installed content for corruption</string> <string name="verify_installed_content_description">Checks all installed content for corruption</string>
<string name="keys_missing">Encryption keys are missing</string>
<string name="keys_missing_description">Firmware and retail games cannot be decrypted</string>
<string name="keys_missing_help">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<!-- Applet launcher strings --> <!-- Applet launcher strings -->
<string name="applets">Applet launcher</string> <string name="applets">Applet launcher</string>

View File

@ -106,6 +106,7 @@ add_library(common STATIC
precompiled_headers.h precompiled_headers.h
quaternion.h quaternion.h
range_map.h range_map.h
range_mutex.h
reader_writer_queue.h reader_writer_queue.h
ring_buffer.h ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp

93
src/common/range_mutex.h Normal file
View File

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include "common/intrusive_list.h"
namespace Common {
class ScopedRangeLock;
class RangeMutex {
public:
explicit RangeMutex() = default;
~RangeMutex() = default;
private:
friend class ScopedRangeLock;
void Lock(ScopedRangeLock& l);
void Unlock(ScopedRangeLock& l);
bool HasIntersectionLocked(ScopedRangeLock& l);
private:
std::mutex m_mutex;
std::condition_variable m_cv;
using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
LockList m_list;
};
class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
public:
explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
: m_mutex(mutex), m_address(address), m_size(size) {
if (m_size > 0) {
m_mutex.Lock(*this);
}
}
~ScopedRangeLock() {
if (m_size > 0) {
m_mutex.Unlock(*this);
}
}
u64 GetAddress() const {
return m_address;
}
u64 GetSize() const {
return m_size;
}
private:
RangeMutex& m_mutex;
const u64 m_address{};
const u64 m_size{};
};
inline void RangeMutex::Lock(ScopedRangeLock& l) {
std::unique_lock lk{m_mutex};
m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
m_list.push_back(l);
}
inline void RangeMutex::Unlock(ScopedRangeLock& l) {
{
std::scoped_lock lk{m_mutex};
m_list.erase(m_list.iterator_to(l));
}
m_cv.notify_all();
}
inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
const auto cur_begin = l.GetAddress();
const auto cur_last = l.GetAddress() + l.GetSize() - 1;
for (const auto& other : m_list) {
const auto other_begin = other.GetAddress();
const auto other_last = other.GetAddress() + other.GetSize() - 1;
if (cur_begin <= other_last && other_begin <= cur_last) {
return true;
}
}
return false;
}
} // namespace Common

View File

@ -10,6 +10,7 @@
#include <mutex> #include <mutex>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/range_mutex.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "common/virtual_buffer.h" #include "common/virtual_buffer.h"
@ -204,7 +205,7 @@ private:
(1ULL << (device_virtual_bits - page_bits)) / subentries; (1ULL << (device_virtual_bits - page_bits)) / subentries;
using CachedPages = std::array<CounterEntry, num_counter_entries>; using CachedPages = std::array<CounterEntry, num_counter_entries>;
std::unique_ptr<CachedPages> cached_pages; std::unique_ptr<CachedPages> cached_pages;
std::mutex counter_guard; Common::RangeMutex counter_guard;
std::mutex mapping_guard; std::mutex mapping_guard;
}; };

View File

@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
template <typename Traits> template <typename Traits>
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); Common::ScopedRangeLock lk(counter_guard, addr, size);
const auto Lock = [&] {
if (!lk) {
lk.lock();
}
};
u64 uncache_begin = 0; u64 uncache_begin = 0;
u64 cache_begin = 0; u64 cache_begin = 0;
u64 uncache_bytes = 0; u64 uncache_bytes = 0;
@ -548,7 +543,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
uncache_bytes += Memory::YUZU_PAGESIZE; uncache_bytes += Memory::YUZU_PAGESIZE;
} else if (uncache_bytes > 0) { } else if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false); uncache_bytes, false);
uncache_bytes = 0; uncache_bytes = 0;
@ -559,7 +553,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
cache_bytes += Memory::YUZU_PAGESIZE; cache_bytes += Memory::YUZU_PAGESIZE;
} else if (cache_bytes > 0) { } else if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
cache_bytes = 0; cache_bytes = 0;
@ -567,12 +560,10 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
vpage++; vpage++;
} }
if (uncache_bytes > 0) { if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
false); false);
} }
if (cache_bytes > 0) { if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
} }

View File

@ -69,9 +69,14 @@ public:
}; };
template <typename AddressType> template <typename AddressType>
void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size) { void InvalidateInstructionCache(KernelCore& kernel, KPageTableBase* table, AddressType addr,
u64 size) {
// TODO: lock the process list // TODO: lock the process list
for (auto& process : kernel.GetProcessList()) { for (auto& process : kernel.GetProcessList()) {
if (std::addressof(process->GetPageTable().GetBasePageTable()) != table) {
continue;
}
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
auto* interface = process->GetArmInterface(i); auto* interface = process->GetArmInterface(i);
if (interface) { if (interface) {
@ -1302,7 +1307,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
bool reprotected_pages = false; bool reprotected_pages = false;
SCOPE_EXIT({ SCOPE_EXIT({
if (reprotected_pages && any_code_pages) { if (reprotected_pages && any_code_pages) {
InvalidateInstructionCache(m_kernel, dst_address, size); InvalidateInstructionCache(m_kernel, this, dst_address, size);
} }
}); });
@ -2036,7 +2041,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s
for (const auto& block : pg) { for (const auto& block : pg) {
StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize()); StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize());
} }
InvalidateInstructionCache(m_kernel, addr, size); InvalidateInstructionCache(m_kernel, this, addr, size);
} }
R_SUCCEED(); R_SUCCEED();
@ -3277,7 +3282,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd
R_TRY(PerformCopy()); R_TRY(PerformCopy());
// Invalidate the instruction cache, as this svc allows modifying executable pages. // Invalidate the instruction cache, as this svc allows modifying executable pages.
InvalidateInstructionCache(m_kernel, dst_address, size); InvalidateInstructionCache(m_kernel, this, dst_address, size);
R_SUCCEED(); R_SUCCEED();
} }

View File

@ -112,6 +112,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
void Container::CloseSession(SessionId session_id) { void Container::CloseSession(SessionId session_id) {
std::scoped_lock lk(impl->session_guard); std::scoped_lock lk(impl->session_guard);
impl->file.UnmapAllHandles(session_id);
auto& session = impl->sessions[session_id.id]; auto& session = impl->sessions[session_id.id];
auto& smmu = impl->host1x.MemoryManager(); auto& smmu = impl->host1x.MemoryManager();
if (session.has_preallocated_area) { if (session.has_preallocated_area) {

View File

@ -326,4 +326,17 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
return freeInfo; return freeInfo;
} }
void NvMap::UnmapAllHandles(NvCore::SessionId session_id) {
auto handles_copy = [&] {
std::scoped_lock lk{handles_lock};
return handles;
}();
for (auto& [id, handle] : handles_copy) {
if (handle->session_id.id == session_id.id) {
FreeHandle(id, false);
}
}
}
} // namespace Service::Nvidia::NvCore } // namespace Service::Nvidia::NvCore

View File

@ -152,6 +152,8 @@ public:
*/ */
std::optional<FreeInfo> FreeHandle(Handle::Id handle, bool internal_session); std::optional<FreeInfo> FreeHandle(Handle::Id handle, bool internal_session);
void UnmapAllHandles(NvCore::SessionId session_id);
private: private:
std::list<std::shared_ptr<Handle>> unmap_queue{}; std::list<std::shared_ptr<Handle>> unmap_queue{};
std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue`

View File

@ -1093,6 +1093,20 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
[&] { rasterizer = true; }); [&] { rasterizer = true; });
if (rasterizer) { if (rasterizer) {
impl->InvalidateGPUMemory(ptr, size); impl->InvalidateGPUMemory(ptr, size);
const auto type = impl->current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type();
if (type == Common::PageType::RasterizerCachedMemory) {
// Check if device mapped. If not, this bugged and we can unmark.
DAddr addr{};
Common::ScratchBuffer<u32> buffer;
impl->gpu_device_memory->ApplyOpOnPointer(ptr, buffer,
[&](DAddr address) { addr = address; });
if (addr == 0) {
LOG_ERROR(HW_Memory, "Fixing unmapped cached region {:#x}", GetInteger(vaddr));
impl->RasterizerMarkRegionCached(GetInteger(vaddr), size, false);
}
}
} }
#ifdef __linux__ #ifdef __linux__

View File

@ -47,14 +47,14 @@ inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_contro
/** /**
* \brief Removes all DLC for a game * \brief Removes all DLC for a game
* \param system Raw pointer to the system instance * \param system Reference to the system instance
* \param program_id Program ID for the game that will have all of its DLC removed * \param program_id Program ID for the game that will have all of its DLC removed
* \return Number of DLC removed * \return Number of DLC removed
*/ */
inline size_t RemoveAllDLC(Core::System* system, const u64 program_id) { inline size_t RemoveAllDLC(Core::System& system, const u64 program_id) {
size_t count{}; size_t count{};
const auto& fs_controller = system->GetFileSystemController(); const auto& fs_controller = system.GetFileSystemController();
const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( const auto dlc_entries = system.GetContentProvider().ListEntriesFilter(
FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::vector<u64> program_dlc_entries; std::vector<u64> program_dlc_entries;
@ -124,15 +124,15 @@ inline bool RemoveMod(const Service::FileSystem::FileSystemController& fs_contro
/** /**
* \brief Installs an NSP * \brief Installs an NSP
* \param system Raw pointer to the system instance * \param system Reference to the system instance
* \param vfs Raw pointer to the VfsFilesystem instance in Core::System * \param vfs Reference to the VfsFilesystem instance in Core::System
* \param filename Path to the NSP file * \param filename Path to the NSP file
* \param callback Callback to report the progress of the installation. The first size_t * \param callback Callback to report the progress of the installation. The first size_t
* parameter is the total size of the virtual file and the second is the current progress. If you * parameter is the total size of the virtual file and the second is the current progress. If you
* return true to the callback, it will cancel the installation as soon as possible. * return true to the callback, it will cancel the installation as soon as possible.
* \return [InstallResult] representing how the installation finished * \return [InstallResult] representing how the installation finished
*/ */
inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vfs, inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vfs,
const std::string& filename, const std::string& filename,
const std::function<bool(size_t, size_t)>& callback) { const std::function<bool(size_t, size_t)>& callback) {
const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
@ -159,7 +159,7 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
}; };
std::shared_ptr<FileSys::NSP> nsp; std::shared_ptr<FileSys::NSP> nsp;
FileSys::VirtualFile file = vfs->OpenFile(filename, FileSys::Mode::Read); FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::Mode::Read);
if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) {
nsp = std::make_shared<FileSys::NSP>(file); nsp = std::make_shared<FileSys::NSP>(file);
if (nsp->IsExtractedType()) { if (nsp->IsExtractedType()) {
@ -173,7 +173,7 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
return InstallResult::Failure; return InstallResult::Failure;
} }
const auto res = const auto res =
system->GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy); system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy);
switch (res) { switch (res) {
case FileSys::InstallResult::Success: case FileSys::InstallResult::Success:
return InstallResult::Success; return InstallResult::Success;
@ -188,17 +188,17 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
/** /**
* \brief Installs an NCA * \brief Installs an NCA
* \param vfs Raw pointer to the VfsFilesystem instance in Core::System * \param vfs Reference to the VfsFilesystem instance in Core::System
* \param filename Path to the NCA file * \param filename Path to the NCA file
* \param registered_cache Raw pointer to the registered cache that the NCA will be installed to * \param registered_cache Reference to the registered cache that the NCA will be installed to
* \param title_type Type of NCA package to install * \param title_type Type of NCA package to install
* \param callback Callback to report the progress of the installation. The first size_t * \param callback Callback to report the progress of the installation. The first size_t
* parameter is the total size of the virtual file and the second is the current progress. If you * parameter is the total size of the virtual file and the second is the current progress. If you
* return true to the callback, it will cancel the installation as soon as possible. * return true to the callback, it will cancel the installation as soon as possible.
* \return [InstallResult] representing how the installation finished * \return [InstallResult] representing how the installation finished
*/ */
inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string& filename, inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string& filename,
FileSys::RegisteredCache* registered_cache, FileSys::RegisteredCache& registered_cache,
const FileSys::TitleType title_type, const FileSys::TitleType title_type,
const std::function<bool(size_t, size_t)>& callback) { const std::function<bool(size_t, size_t)>& callback) {
const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
@ -224,7 +224,7 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
return true; return true;
}; };
const auto nca = std::make_shared<FileSys::NCA>(vfs->OpenFile(filename, FileSys::Mode::Read)); const auto nca = std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::Mode::Read));
const auto id = nca->GetStatus(); const auto id = nca->GetStatus();
// Game updates necessary are missing base RomFS // Game updates necessary are missing base RomFS
@ -233,7 +233,7 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
return InstallResult::Failure; return InstallResult::Failure;
} }
const auto res = registered_cache->InstallEntry(*nca, title_type, true, copy); const auto res = registered_cache.InstallEntry(*nca, title_type, true, copy);
if (res == FileSys::InstallResult::Success) { if (res == FileSys::InstallResult::Success) {
return InstallResult::Success; return InstallResult::Success;
} else if (res == FileSys::InstallResult::OverwriteExisting) { } else if (res == FileSys::InstallResult::OverwriteExisting) {
@ -245,19 +245,19 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
/** /**
* \brief Verifies the installed contents for a given ManualContentProvider * \brief Verifies the installed contents for a given ManualContentProvider
* \param system Raw pointer to the system instance * \param system Reference to the system instance
* \param provider Raw pointer to the content provider that's tracking indexed games * \param provider Reference to the content provider that's tracking indexed games
* \param callback Callback to report the progress of the installation. The first size_t * \param callback Callback to report the progress of the installation. The first size_t
* parameter is the total size of the installed contents and the second is the current progress. If * parameter is the total size of the installed contents and the second is the current progress. If
* you return true to the callback, it will cancel the installation as soon as possible. * you return true to the callback, it will cancel the installation as soon as possible.
* \return A list of entries that failed to install. Returns an empty vector if successful. * \return A list of entries that failed to install. Returns an empty vector if successful.
*/ */
inline std::vector<std::string> VerifyInstalledContents( inline std::vector<std::string> VerifyInstalledContents(
Core::System* system, FileSys::ManualContentProvider* provider, Core::System& system, FileSys::ManualContentProvider& provider,
const std::function<bool(size_t, size_t)>& callback) { const std::function<bool(size_t, size_t)>& callback) {
// Get content registries. // Get content registries.
auto bis_contents = system->GetFileSystemController().GetSystemNANDContents(); auto bis_contents = system.GetFileSystemController().GetSystemNANDContents();
auto user_contents = system->GetFileSystemController().GetUserNANDContents(); auto user_contents = system.GetFileSystemController().GetUserNANDContents();
std::vector<FileSys::RegisteredCache*> content_providers; std::vector<FileSys::RegisteredCache*> content_providers;
if (bis_contents) { if (bis_contents) {
@ -309,11 +309,11 @@ inline std::vector<std::string> VerifyInstalledContents(
const auto title_id = nca.GetTitleId(); const auto title_id = nca.GetTitleId();
std::string title_name = "unknown"; std::string title_name = "unknown";
const auto control = provider->GetEntry(FileSys::GetBaseTitleID(title_id), const auto control = provider.GetEntry(FileSys::GetBaseTitleID(title_id),
FileSys::ContentRecordType::Control); FileSys::ContentRecordType::Control);
if (control && control->GetStatus() == Loader::ResultStatus::Success) { if (control && control->GetStatus() == Loader::ResultStatus::Success) {
const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
*provider}; provider};
const auto [nacp, logo] = pm.ParseControlNCA(*control); const auto [nacp, logo] = pm.ParseControlNCA(*control);
if (nacp) { if (nacp) {
title_name = nacp->GetApplicationName(); title_name = nacp->GetApplicationName();
@ -335,7 +335,7 @@ inline std::vector<std::string> VerifyInstalledContents(
/** /**
* \brief Verifies the contents of a given game * \brief Verifies the contents of a given game
* \param system Raw pointer to the system instance * \param system Reference to the system instance
* \param game_path Patch to the game file * \param game_path Patch to the game file
* \param callback Callback to report the progress of the installation. The first size_t * \param callback Callback to report the progress of the installation. The first size_t
* parameter is the total size of the installed contents and the second is the current progress. If * parameter is the total size of the installed contents and the second is the current progress. If
@ -343,10 +343,10 @@ inline std::vector<std::string> VerifyInstalledContents(
* \return GameVerificationResult representing how the verification process finished * \return GameVerificationResult representing how the verification process finished
*/ */
inline GameVerificationResult VerifyGameContents( inline GameVerificationResult VerifyGameContents(
Core::System* system, const std::string& game_path, Core::System& system, const std::string& game_path,
const std::function<bool(size_t, size_t)>& callback) { const std::function<bool(size_t, size_t)>& callback) {
const auto loader = Loader::GetLoader( const auto loader =
*system, system->GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read)); Loader::GetLoader(system, system.GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read));
if (loader == nullptr) { if (loader == nullptr) {
return GameVerificationResult::NotImplemented; return GameVerificationResult::NotImplemented;
} }
@ -368,4 +368,11 @@ inline GameVerificationResult VerifyGameContents(
return GameVerificationResult::Success; return GameVerificationResult::Success;
} }
/**
* Checks if the keys required for decrypting firmware and games are available
*/
inline bool AreKeysPresent() {
return !Core::Crypto::KeyManager::Instance().BaseDeriveNecessary();
}
} // namespace ContentManager } // namespace ContentManager

View File

@ -110,7 +110,11 @@ void EmulatedController::ReloadFromSettings() {
original_npad_type = npad_type; original_npad_type = npad_type;
} }
// Disable special features before disconnecting
if (controller.right_polling_mode != Common::Input::PollingMode::Active) {
SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active); SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active);
}
Disconnect(); Disconnect();
if (player.connected) { if (player.connected) {
Connect(); Connect();
@ -1241,7 +1245,12 @@ bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationV
return false; return false;
} }
last_vibration_value = vibration; // Skip duplicated vibrations
if (last_vibration_value[index] == vibration) {
return Settings::values.vibration_enabled.GetValue();
}
last_vibration_value[index] = vibration;
if (!Settings::values.vibration_enabled) { if (!Settings::values.vibration_enabled) {
return false; return false;
@ -1272,7 +1281,10 @@ bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationV
} }
VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const { VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const {
return last_vibration_value; if (device_index >= DeviceIndex::MaxDeviceIndex) {
return Core::HID::DEFAULT_VIBRATION_VALUE;
}
return last_vibration_value[static_cast<std::size_t>(device_index)];
} }
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {

View File

@ -581,7 +581,8 @@ private:
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
u32 turbo_button_state{0}; u32 turbo_button_state{0};
std::size_t nfc_handles{0}; std::size_t nfc_handles{0};
VibrationValue last_vibration_value{DEFAULT_VIBRATION_VALUE}; std::array<VibrationValue, 2> last_vibration_value{DEFAULT_VIBRATION_VALUE,
DEFAULT_VIBRATION_VALUE};
// Temporary values to avoid doing changes while the controller is in configuring mode // Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};

View File

@ -639,6 +639,15 @@ struct VibrationValue {
f32 low_frequency{}; f32 low_frequency{};
f32 high_amplitude{}; f32 high_amplitude{};
f32 high_frequency{}; f32 high_frequency{};
bool operator==(const VibrationValue& b) {
if (low_amplitude != b.low_amplitude || high_amplitude != b.high_amplitude) {
return false;
}
if (low_frequency != b.low_amplitude || high_frequency != b.high_frequency) {
return false;
}
return true;
}
}; };
static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");

View File

@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
std::span<const u8> upload_span; std::span<const u8> upload_span;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (IsRangeGranular(device_addr, copy.size)) { if (IsRangeGranular(device_addr, copy.size)) {
upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size); auto* const ptr = device_memory.GetPointer<u8>(device_addr);
if (ptr != nullptr) {
upload_span = std::span(ptr, copy.size);
}
} else { } else {
if (immediate_buffer.empty()) { if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy); immediate_buffer = ImmediateBuffer(largest_copy);

View File

@ -243,10 +243,12 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
const u64 size_in_bytes{Tegra::Texture::CalculateSize( const u64 size_in_bytes{Tegra::Texture::CalculateSize(
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
if (host_ptr != nullptr) {
const std::span<const u8> input_data(host_ptr, size_in_bytes); const std::span<const u8> input_data(host_ptr, size_in_bytes);
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
framebuffer.width, framebuffer.height, 1, block_height_log2, framebuffer.width, framebuffer.height, 1,
0); block_height_log2, 0);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));

View File

@ -230,9 +230,11 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel,
framebuffer.stride, framebuffer.height, framebuffer.stride, framebuffer.height,
1, block_height_log2, 0)}; 1, block_height_log2, 0)};
if (host_ptr != nullptr) {
Tegra::Texture::UnswizzleTexture( Tegra::Texture::UnswizzleTexture(
mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
}
const VkBufferImageCopy copy{ const VkBufferImageCopy copy{
.bufferOffset = image_offset, .bufferOffset = image_offset,

View File

@ -1064,8 +1064,6 @@ public:
} }
}); });
} }
auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address);
ASSERT(ptr != nullptr);
new_query->dependant_manage = must_manage_dependance; new_query->dependant_manage = must_manage_dependance;
pending_flush_queries.push_back(index); pending_flush_queries.push_back(index);
@ -1104,10 +1102,12 @@ public:
tfb_streamer.Free(query->dependant_index); tfb_streamer.Free(query->dependant_index);
} else { } else {
u8* pointer = device_memory.GetPointer<u8>(query->dependant_address); u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
if (pointer != nullptr) {
u32 result; u32 result;
std::memcpy(&result, pointer, sizeof(u32)); std::memcpy(&result, pointer, sizeof(u32));
num_vertices = static_cast<u64>(result) / query->stride; num_vertices = static_cast<u64>(result) / query->stride;
} }
}
query->value = [&]() -> u64 { query->value = [&]() -> u64 {
switch (query->topology) { switch (query->topology) {
case Maxwell3D::Regs::PrimitiveTopology::Points: case Maxwell3D::Regs::PrimitiveTopology::Points:
@ -1360,7 +1360,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
const auto check_value = [&](DAddr address) { const auto check_value = [&](DAddr address) {
u8* ptr = impl->device_memory.GetPointer<u8>(address); u8* ptr = impl->device_memory.GetPointer<u8>(address);
u64 value{}; u64 value{};
if (ptr != nullptr) {
std::memcpy(&value, ptr, sizeof(value)); std::memcpy(&value, ptr, sizeof(value));
}
return value == 0; return value == 0;
}; };
std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2}; std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2};

View File

@ -423,7 +423,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
RemoveCachedContents(); RemoveCachedContents();
// Gen keys if necessary // Gen keys if necessary
OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning); OnCheckFirmwareDecryption();
game_list->LoadCompatibilityList(); game_list->LoadCompatibilityList();
game_list->PopulateAsync(UISettings::values.game_dirs); game_list->PopulateAsync(UISettings::values.game_dirs);
@ -1574,8 +1574,6 @@ void GMainWindow::ConnectMenuEvents() {
connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig); connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);
// Tools // Tools
connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
ReinitializeKeyBehavior::Warning));
connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum); connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
connect_menu(ui->action_Load_Cabinet_Nickname_Owner, connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); }); [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
@ -2501,7 +2499,7 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) {
} }
void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) {
const size_t count = ContentManager::RemoveAllDLC(system.get(), program_id); const size_t count = ContentManager::RemoveAllDLC(*system, program_id);
if (count == 0) { if (count == 0) {
QMessageBox::warning(this, GetGameListErrorRemoving(type), QMessageBox::warning(this, GetGameListErrorRemoving(type),
tr("There are no DLC installed for this title.")); tr("There are no DLC installed for this title."));
@ -2798,8 +2796,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
return progress.wasCanceled(); return progress.wasCanceled();
}; };
const auto result = const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback);
ContentManager::VerifyGameContents(system.get(), game_path, QtProgressCallback);
progress.close(); progress.close();
switch (result) { switch (result) {
case ContentManager::GameVerificationResult::Success: case ContentManager::GameVerificationResult::Success:
@ -3268,7 +3265,7 @@ void GMainWindow::OnMenuInstallToNAND() {
return false; return false;
}; };
future = QtConcurrent::run([this, &file, progress_callback] { future = QtConcurrent::run([this, &file, progress_callback] {
return ContentManager::InstallNSP(system.get(), vfs.get(), file.toStdString(), return ContentManager::InstallNSP(*system, *vfs, file.toStdString(),
progress_callback); progress_callback);
}); });
@ -3371,7 +3368,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) {
} }
return false; return false;
}; };
return ContentManager::InstallNCA(vfs.get(), filename.toStdString(), registered_cache, return ContentManager::InstallNCA(*vfs, filename.toStdString(), *registered_cache,
static_cast<FileSys::TitleType>(index), progress_callback); static_cast<FileSys::TitleType>(index), progress_callback);
} }
@ -4121,7 +4118,7 @@ void GMainWindow::OnVerifyInstalledContents() {
}; };
const std::vector<std::string> result = const std::vector<std::string> result =
ContentManager::VerifyInstalledContents(system.get(), provider.get(), QtProgressCallback); ContentManager::VerifyInstalledContents(*system, *provider, QtProgressCallback);
progress.close(); progress.close();
if (result.empty()) { if (result.empty()) {
@ -4551,122 +4548,20 @@ void GMainWindow::OnMouseActivity() {
} }
} }
void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { void GMainWindow::OnCheckFirmwareDecryption() {
if (behavior == ReinitializeKeyBehavior::Warning) {
const auto res = QMessageBox::information(
this, tr("Confirm Key Rederivation"),
tr("You are about to force rederive all of your keys. \nIf you do not know what "
"this "
"means or what you are doing, \nthis is a potentially destructive action. "
"\nPlease "
"make sure this is what you want \nand optionally make backups.\n\nThis will "
"delete "
"your autogenerated key files and re-run the key derivation module."),
QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
if (res == QMessageBox::Cancel)
return;
const auto keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated");
Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated");
Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated");
}
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
bool all_keys_present{true};
if (keys.BaseDeriveNecessary()) {
Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory("", FileSys::Mode::Read)};
const auto function = [this, &keys, &pdm] {
keys.PopulateFromPartitionData(pdm);
system->GetFileSystemController().CreateFactories(*vfs); system->GetFileSystemController().CreateFactories(*vfs);
keys.DeriveETicket(pdm, system->GetContentProvider()); if (!ContentManager::AreKeysPresent()) {
};
QString errors;
if (!pdm.HasFuses()) {
errors += tr("Missing fuses");
}
if (!pdm.HasBoot0()) {
errors += tr(" - Missing BOOT0");
}
if (!pdm.HasPackage2()) {
errors += tr(" - Missing BCPKG2-1-Normal-Main");
}
if (!pdm.HasProdInfo()) {
errors += tr(" - Missing PRODINFO");
}
if (!errors.isEmpty()) {
all_keys_present = false;
QMessageBox::warning( QMessageBox::warning(
this, tr("Derivation Components Missing"), this, tr("Derivation Components Missing"),
tr("Encryption keys are missing. " tr("Encryption keys are missing. "
"<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
"quickstart guide</a> to get all your keys, firmware and "
"games.<br><br><small>(%1)</small>")
.arg(errors));
}
QProgressDialog prog(this);
prog.setRange(0, 0);
prog.setLabelText(tr("Deriving keys...\nThis may take up to a minute depending \non your "
"system's performance."));
prog.setWindowTitle(tr("Deriving Keys"));
prog.show();
auto future = QtConcurrent::run(function);
while (!future.isFinished()) {
QCoreApplication::processEvents();
}
prog.close();
}
system->GetFileSystemController().CreateFactories(*vfs);
if (all_keys_present && !this->CheckSystemArchiveDecryption()) {
LOG_WARNING(Frontend, "Mii model decryption failed");
QMessageBox::warning(
this, tr("System Archive Decryption Failed"),
tr("Encryption keys failed to decrypt firmware. "
"<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu " "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
"quickstart guide</a> to get all your keys, firmware and " "quickstart guide</a> to get all your keys, firmware and "
"games.")); "games."));
} }
SetFirmwareVersion(); SetFirmwareVersion();
if (behavior == ReinitializeKeyBehavior::Warning) {
game_list->PopulateAsync(UISettings::values.game_dirs);
}
UpdateMenuState(); UpdateMenuState();
} }
bool GMainWindow::CheckSystemArchiveDecryption() {
constexpr u64 MiiModelId = 0x0100000000000802;
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
// Not having system BIS files is not an error.
return true;
}
auto mii_nca = bis_system->GetEntry(MiiModelId, FileSys::ContentRecordType::Data);
if (!mii_nca) {
// Not having the Mii model is not an error.
return true;
}
// Return whether we are able to decrypt the RomFS of the Mii model.
return mii_nca->GetRomFS().get() != nullptr;
}
bool GMainWindow::CheckFirmwarePresence() { bool GMainWindow::CheckFirmwarePresence() {
constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit);

View File

@ -125,11 +125,6 @@ enum class EmulatedDirectoryTarget {
SDMC, SDMC,
}; };
enum class ReinitializeKeyBehavior {
NoWarning,
Warning,
};
namespace VkDeviceInfo { namespace VkDeviceInfo {
class Record; class Record;
} }
@ -400,7 +395,7 @@ private slots:
void OnMiiEdit(); void OnMiiEdit();
void OnOpenControllerMenu(); void OnOpenControllerMenu();
void OnCaptureScreenshot(); void OnCaptureScreenshot();
void OnReinitializeKeys(ReinitializeKeyBehavior behavior); void OnCheckFirmwareDecryption();
void OnLanguageChanged(const QString& locale); void OnLanguageChanged(const QString& locale);
void OnMouseActivity(); void OnMouseActivity();
bool OnShutdownBegin(); bool OnShutdownBegin();
@ -441,7 +436,6 @@ private:
void LoadTranslation(); void LoadTranslation();
void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
bool CheckDarkMode(); bool CheckDarkMode();
bool CheckSystemArchiveDecryption();
bool CheckFirmwarePresence(); bool CheckFirmwarePresence();
void SetFirmwareVersion(); void SetFirmwareVersion();
void ConfigureFilesystemProvider(const std::string& filepath); void ConfigureFilesystemProvider(const std::string& filepath);

View File

@ -224,11 +224,6 @@
<string>&amp;Stop</string> <string>&amp;Stop</string>
</property> </property>
</action> </action>
<action name="action_Rederive">
<property name="text">
<string>&amp;Reinitialize keys...</string>
</property>
</action>
<action name="action_Verify_installed_contents"> <action name="action_Verify_installed_contents">
<property name="text"> <property name="text">
<string>&amp;Verify Installed Contents</string> <string>&amp;Verify Installed Contents</string>