mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-11-01 20:01:53 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbfe0c95fa |
@@ -165,13 +165,10 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi
|
||||
const Common::ProcessAddress addr =
|
||||
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
||||
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
||||
const auto result = memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE);
|
||||
if (result == Memory::NCEAccessFaultAction::Retry) {
|
||||
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
|
||||
// We handled the access successfully and are returning to guest code.
|
||||
return true;
|
||||
}
|
||||
if (result == Memory::NCEAccessFaultAction::Instruction) {
|
||||
return HandleGuestAlignmentFault(guest_ctx, raw_info, raw_context);
|
||||
}
|
||||
|
||||
// We couldn't handle the access.
|
||||
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
|
||||
}
|
||||
|
||||
// Critical section for thread cleanup.
|
||||
// Critical section for thread cleanup
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
// Cache values before releasing thread
|
||||
|
||||
@@ -60,20 +60,17 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
|
||||
auto titlekey =
|
||||
keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id_u128[1], rights_id_u128[0]);
|
||||
if (titlekey == Core::Crypto::Key128{}) {
|
||||
status = Loader::ResultStatus::ErrorMissingTitlekey;
|
||||
return;
|
||||
// Fallback: use rights_id as TitleKey for direct dumps without tickets/keys.
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
+8
-13
@@ -739,7 +739,7 @@ struct Memory::Impl {
|
||||
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;
|
||||
const size_t core = (std::min)(system.GetCurrentHostThreadID(),
|
||||
sys_core); // any other calls threads go to syscore.
|
||||
@@ -755,13 +755,9 @@ struct Memory::Impl {
|
||||
sys_core_guard.unlock();
|
||||
}
|
||||
};
|
||||
bool has_pending_writes = false;
|
||||
auto& gpu = system.GPU();
|
||||
gpu_device_memory->ApplyOpOnPointer(
|
||||
p, scratch_buffers[core], [&](DAddr address) { has_pending_writes |= gpu.MustFlushRegion(address, size); });
|
||||
if (has_pending_writes) return false;
|
||||
gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
|
||||
return true;
|
||||
p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
|
||||
}
|
||||
|
||||
Core::System& system;
|
||||
@@ -965,7 +961,7 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool 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 rasterizer = false;
|
||||
|
||||
@@ -977,18 +973,17 @@ NCEAccessFaultAction Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t
|
||||
mapped = false;
|
||||
},
|
||||
[&] { rasterizer = true; });
|
||||
if (rasterizer) {
|
||||
impl->InvalidateGPUMemory(ptr, size);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->host_buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rasterizer) {
|
||||
if (!impl->TryInvalidateGPUMemory(ptr, size)) {
|
||||
return NCEAccessFaultAction::Instruction;
|
||||
}
|
||||
}
|
||||
return mapped && ptr != nullptr ? NCEAccessFaultAction::Retry : NCEAccessFaultAction::Unmapped;
|
||||
return mapped && ptr != nullptr;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
|
||||
+2
-8
@@ -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-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_PAGEMASK = YUZU_PAGESIZE - 1;
|
||||
|
||||
enum class NCEAccessFaultAction {
|
||||
Unmapped,
|
||||
Retry,
|
||||
Instruction,
|
||||
};
|
||||
|
||||
/// Virtual user-space memory regions
|
||||
enum : u64 {
|
||||
/// TLS (Thread-Local Storage) related.
|
||||
@@ -499,7 +493,7 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -125,8 +125,7 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
|
||||
ClearDownload(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,IsRegionGpuModified(page_start, Common::AlignUp(device_addr + size, DEVICE_PAGESIZE) - page_start));
|
||||
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -154,7 +153,7 @@ bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
||||
if (!is_dirty) {
|
||||
return false;
|
||||
}
|
||||
if (IsRegionGpuModified(device_addr, size)) {
|
||||
if (memory_tracker.IsRegionGpuModified(device_addr, size)) {
|
||||
return true;
|
||||
}
|
||||
WriteMemory(device_addr, size);
|
||||
@@ -1782,23 +1781,13 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
|
||||
u64 largest_copy = 0;
|
||||
DAddr buffer_start = buffer.CpuAddr();
|
||||
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
|
||||
const auto add_upload = [&](DAddr start, DAddr end) {
|
||||
if (start == end) return;
|
||||
const u64 upload_size = end - start;
|
||||
copies.push_back(BufferCopy{
|
||||
.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;
|
||||
copies.push_back(BufferCopy{
|
||||
.src_offset = total_size_bytes,
|
||||
.dst_offset = device_addr_out - buffer_start,
|
||||
.size = range_size,
|
||||
});
|
||||
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) {
|
||||
return true;
|
||||
|
||||
@@ -71,9 +71,9 @@ public:
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
IteratePages<true>(dirty_cpu_addr, query_size, [keep_tracking](Manager* manager, u64 offset, size_t size) {
|
||||
manager->ChangeRegionState(Type::CPU, true, manager->cpu_addr + offset, size, keep_tracking);
|
||||
void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -115,20 +115,19 @@ struct WordManager {
|
||||
/// @param enable If enabling or disabling
|
||||
/// @param dirty_addr Base address 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, bool keep_tracking = false) noexcept {
|
||||
void ChangeRegionState(Type type, bool enable, u64 dirty_addr, u64 size) noexcept {
|
||||
std::span<u64> state_words = Span(type);
|
||||
[[maybe_unused]] std::span<u64> untracked_words = Span(Type::Untracked);
|
||||
[[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU);
|
||||
std::vector<std::pair<VAddr, u64>> ranges;
|
||||
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
|
||||
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) {
|
||||
state_words[index] |= mask;
|
||||
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)
|
||||
cached_words[index] &= ~mask;
|
||||
} else {
|
||||
@@ -140,7 +139,7 @@ struct WordManager {
|
||||
}
|
||||
});
|
||||
if (!ranges.empty()) {
|
||||
ApplyCollectedRanges(ranges, (!enable || keep_tracking) ? 1 : -1);
|
||||
ApplyCollectedRanges(ranges, (!enable) ? 1 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,10 +234,6 @@ struct GPU::Impl {
|
||||
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
|
||||
void FlushAndInvalidateRegion(DAddr addr, u64 size) {
|
||||
gpu_thread.FlushAndInvalidateRegion(addr, size, is_async);
|
||||
@@ -530,10 +526,6 @@ bool GPU::OnCPUWrite(DAddr addr, u64 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) {
|
||||
impl->FlushAndInvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
@@ -254,9 +254,6 @@ public:
|
||||
/// sensible, false otherwise, addr and size must be a valid combination
|
||||
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
|
||||
void FlushAndInvalidateRegion(DAddr addr, u64 size);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user