Compare commits

..

1 Commits

Author SHA1 Message Date
PavelBARABANOV fbfe0c95fa [fyle_sys] Fall back to RightsId as TitleKey for direct dumps 2026-11-01 07:40:26 +03:00
9 changed files with 37 additions and 77 deletions
+3 -6
View File
@@ -165,13 +165,10 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi
const Common::ProcessAddress addr = const Common::ProcessAddress addr =
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK); (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
const auto result = memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE); if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
if (result == Memory::NCEAccessFaultAction::Retry) { // We handled the access successfully and are returning to guest code.
return true; return true;
} }
if (result == Memory::NCEAccessFaultAction::Instruction) {
return HandleGuestAlignmentFault(guest_ctx, raw_info, raw_context);
}
// We couldn't handle the access. // We couldn't handle the access.
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
@@ -234,7 +231,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) {
hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging
} }
// Critical section for thread cleanup. // Critical section for thread cleanup
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
// Cache values before releasing thread // Cache values before releasing thread
+9 -12
View File
@@ -60,20 +60,17 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
auto titlekey = auto titlekey =
keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id_u128[1], rights_id_u128[0]); keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id_u128[1], rights_id_u128[0]);
if (titlekey == Core::Crypto::Key128{}) { if (titlekey == Core::Crypto::Key128{}) {
status = Loader::ResultStatus::ErrorMissingTitlekey; // Fallback: use rights_id as TitleKey for direct dumps without tickets/keys.
return; std::memcpy(titlekey.data(), rights_id.data(), rights_id.size());
LOG_DEBUG(Loader, "TitleKey not found for {}, falling back to RightsId.",
file->GetName());
} else if (keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
auto titlekek = keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id);
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(titlekek, Core::Crypto::Mode::ECB);
cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(),
Core::Crypto::Op::Decrypt);
} }
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
status = Loader::ResultStatus::ErrorMissingTitlekek;
return;
}
auto titlekek = keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id);
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(titlekek, Core::Crypto::Mode::ECB);
cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(),
Core::Crypto::Op::Decrypt);
reader->SetExternalDecryptionKey(titlekey.data(), titlekey.size()); reader->SetExternalDecryptionKey(titlekey.data(), titlekey.size());
} }
+8 -13
View File
@@ -739,7 +739,7 @@ struct Memory::Impl {
PAddr last_address; PAddr last_address;
}; };
bool TryInvalidateGPUMemory(const u8* p, size_t size) { void InvalidateGPUMemory(u8* p, size_t size) {
constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
const size_t core = (std::min)(system.GetCurrentHostThreadID(), const size_t core = (std::min)(system.GetCurrentHostThreadID(),
sys_core); // any other calls threads go to syscore. sys_core); // any other calls threads go to syscore.
@@ -755,13 +755,9 @@ struct Memory::Impl {
sys_core_guard.unlock(); sys_core_guard.unlock();
} }
}; };
bool has_pending_writes = false;
auto& gpu = system.GPU(); auto& gpu = system.GPU();
gpu_device_memory->ApplyOpOnPointer( gpu_device_memory->ApplyOpOnPointer(
p, scratch_buffers[core], [&](DAddr address) { has_pending_writes |= gpu.MustFlushRegion(address, size); }); p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
if (has_pending_writes) return false;
gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
return true;
} }
Core::System& system; Core::System& system;
@@ -965,7 +961,7 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug)
impl->MarkRegionDebug(GetInteger(vaddr), size, debug); impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
} }
NCEAccessFaultAction Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
[[maybe_unused]] bool mapped = true; [[maybe_unused]] bool mapped = true;
[[maybe_unused]] bool rasterizer = false; [[maybe_unused]] bool rasterizer = false;
@@ -977,18 +973,17 @@ NCEAccessFaultAction Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t
mapped = false; mapped = false;
}, },
[&] { rasterizer = true; }); [&] { rasterizer = true; });
if (rasterizer) {
impl->InvalidateGPUMemory(ptr, size);
}
#ifdef __ANDROID__ #ifdef __ANDROID__
if (!rasterizer && mapped) { if (!rasterizer && mapped) {
impl->host_buffer->DeferredMapSeparateHeap(GetInteger(vaddr)); impl->host_buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
} }
#endif #endif
if (rasterizer) { return mapped && ptr != nullptr;
if (!impl->TryInvalidateGPUMemory(ptr, size)) {
return NCEAccessFaultAction::Instruction;
}
}
return mapped && ptr != nullptr ? NCEAccessFaultAction::Retry : NCEAccessFaultAction::Unmapped;
} }
bool Memory::InvalidateSeparateHeap(void* fault_address) { bool Memory::InvalidateSeparateHeap(void* fault_address) {
+2 -8
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
@@ -46,12 +46,6 @@ constexpr std::size_t YUZU_PAGEBITS = 12;
constexpr u64 YUZU_PAGESIZE = 1ULL << YUZU_PAGEBITS; constexpr u64 YUZU_PAGESIZE = 1ULL << YUZU_PAGEBITS;
constexpr u64 YUZU_PAGEMASK = YUZU_PAGESIZE - 1; constexpr u64 YUZU_PAGEMASK = YUZU_PAGESIZE - 1;
enum class NCEAccessFaultAction {
Unmapped,
Retry,
Instruction,
};
/// Virtual user-space memory regions /// Virtual user-space memory regions
enum : u64 { enum : u64 {
/// TLS (Thread-Local Storage) related. /// TLS (Thread-Local Storage) related.
@@ -499,7 +493,7 @@ public:
void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
NCEAccessFaultAction InvalidateNCE(Common::ProcessAddress vaddr, size_t size); bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
bool InvalidateSeparateHeap(void* fault_address); bool InvalidateSeparateHeap(void* fault_address);
+8 -19
View File
@@ -125,8 +125,7 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
ClearDownload(device_addr, size); ClearDownload(device_addr, size);
gpu_modified_ranges.Subtract(device_addr, size); gpu_modified_ranges.Subtract(device_addr, size);
} }
const DAddr page_start = Common::AlignDown(device_addr, DEVICE_PAGESIZE); memory_tracker.MarkRegionAsCpuModified(device_addr, size);
memory_tracker.MarkRegionAsCpuModified(device_addr, size,IsRegionGpuModified(page_start, Common::AlignUp(device_addr + size, DEVICE_PAGESIZE) - page_start));
} }
template <class P> template <class P>
@@ -154,7 +153,7 @@ bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
if (!is_dirty) { if (!is_dirty) {
return false; return false;
} }
if (IsRegionGpuModified(device_addr, size)) { if (memory_tracker.IsRegionGpuModified(device_addr, size)) {
return true; return true;
} }
WriteMemory(device_addr, size); WriteMemory(device_addr, size);
@@ -1782,23 +1781,13 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
u64 largest_copy = 0; u64 largest_copy = 0;
DAddr buffer_start = buffer.CpuAddr(); DAddr buffer_start = buffer.CpuAddr();
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) { memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
const auto add_upload = [&](DAddr start, DAddr end) { copies.push_back(BufferCopy{
if (start == end) return; .src_offset = total_size_bytes,
const u64 upload_size = end - start; .dst_offset = device_addr_out - buffer_start,
copies.push_back(BufferCopy{ .size = range_size,
.src_offset = total_size_bytes,
.dst_offset = start - buffer_start,
.size = upload_size,
});
total_size_bytes += upload_size;
largest_copy = (std::max)(largest_copy, upload_size);
};
DAddr upload_start = device_addr_out;
gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, [&](DAddr gpu_start, DAddr gpu_end) {
add_upload(upload_start, gpu_start);
upload_start = gpu_end;
}); });
add_upload(upload_start, device_addr_out + range_size); total_size_bytes += range_size;
largest_copy = (std::max)(largest_copy, range_size);
}); });
if (total_size_bytes == 0) { if (total_size_bytes == 0) {
return true; return true;
@@ -71,9 +71,9 @@ public:
} }
/// Mark region as CPU modified, notifying the device_tracker about this change /// Mark region as CPU modified, notifying the device_tracker about this change
void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size, bool keep_tracking = false) { void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
IteratePages<true>(dirty_cpu_addr, query_size, [keep_tracking](Manager* manager, u64 offset, size_t size) { IteratePages<true>(dirty_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
manager->ChangeRegionState(Type::CPU, true, manager->cpu_addr + offset, size, keep_tracking); manager->ChangeRegionState(Type::CPU, true, manager->cpu_addr + offset, size);
}); });
} }
+4 -5
View File
@@ -115,20 +115,19 @@ struct WordManager {
/// @param enable If enabling or disabling /// @param enable If enabling or disabling
/// @param dirty_addr Base address to mark or unmark as modified /// @param dirty_addr Base address to mark or unmark as modified
/// @param size Size in bytes to mark or unmark as modified /// @param size Size in bytes to mark or unmark as modified
/// @param keep_tracking Keep CPU-modified pages protected for subsequent native writes. void ChangeRegionState(Type type, bool enable, u64 dirty_addr, u64 size) noexcept {
void ChangeRegionState(Type type, bool enable, u64 dirty_addr, u64 size, bool keep_tracking = false) noexcept {
std::span<u64> state_words = Span(type); std::span<u64> state_words = Span(type);
[[maybe_unused]] std::span<u64> untracked_words = Span(Type::Untracked); [[maybe_unused]] std::span<u64> untracked_words = Span(Type::Untracked);
[[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU); [[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU);
std::vector<std::pair<VAddr, u64>> ranges; std::vector<std::pair<VAddr, u64>> ranges;
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) { IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
if (type == Type::CPU || type == Type::CachedCPU) { if (type == Type::CPU || type == Type::CachedCPU) {
CollectChangedRanges(!enable || keep_tracking, index, untracked_words[index], mask, ranges); CollectChangedRanges(!enable, index, untracked_words[index], mask, ranges);
} }
if (enable) { if (enable) {
state_words[index] |= mask; state_words[index] |= mask;
if (type == Type::CPU || type == Type::CachedCPU) if (type == Type::CPU || type == Type::CachedCPU)
untracked_words[index] = (untracked_words[index] & ~mask) | (keep_tracking ? u64{0} : mask); untracked_words[index] |= mask;
if (type == Type::CPU) if (type == Type::CPU)
cached_words[index] &= ~mask; cached_words[index] &= ~mask;
} else { } else {
@@ -140,7 +139,7 @@ struct WordManager {
} }
}); });
if (!ranges.empty()) { if (!ranges.empty()) {
ApplyCollectedRanges(ranges, (!enable || keep_tracking) ? 1 : -1); ApplyCollectedRanges(ranges, (!enable) ? 1 : -1);
} }
} }
-8
View File
@@ -234,10 +234,6 @@ struct GPU::Impl {
return renderer->ReadRasterizer()->OnCPUWrite(addr, size); return renderer->ReadRasterizer()->OnCPUWrite(addr, size);
} }
bool MustFlushRegion(DAddr addr, u64 size) {
return renderer->ReadRasterizer()->MustFlushRegion(addr, size);
}
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(DAddr addr, u64 size) { void FlushAndInvalidateRegion(DAddr addr, u64 size) {
gpu_thread.FlushAndInvalidateRegion(addr, size, is_async); gpu_thread.FlushAndInvalidateRegion(addr, size, is_async);
@@ -530,10 +526,6 @@ bool GPU::OnCPUWrite(DAddr addr, u64 size) {
return impl->OnCPUWrite(addr, size); return impl->OnCPUWrite(addr, size);
} }
bool GPU::MustFlushRegion(DAddr addr, u64 size) {
return impl->MustFlushRegion(addr, size);
}
void GPU::FlushAndInvalidateRegion(DAddr addr, u64 size) { void GPU::FlushAndInvalidateRegion(DAddr addr, u64 size) {
impl->FlushAndInvalidateRegion(addr, size); impl->FlushAndInvalidateRegion(addr, size);
} }
-3
View File
@@ -254,9 +254,6 @@ public:
/// sensible, false otherwise, addr and size must be a valid combination /// sensible, false otherwise, addr and size must be a valid combination
bool OnCPUWrite(DAddr addr, u64 size); bool OnCPUWrite(DAddr addr, u64 size);
/// Check whether this range still has GPU writes that must be flushed to CPU memory.
bool MustFlushRegion(DAddr addr, u64 size);
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(DAddr addr, u64 size); void FlushAndInvalidateRegion(DAddr addr, u64 size);