mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 05:28:56 +02:00
[NCE] Fix cache invalidation and signal interrupt race condition (#3063)
Inspired by PR #3047 This should theoretically fix 3 bugs in NCE: - **Bug 1**: `ClearInstructionCache()` now properly invalidates L1 instruction cache using IC IALLU instead of only using memory barriers - **Bug 2**: `InvalidateCacheRange()` implements proper range-based cache invalidation instead of always flushing entire L1 cache - **Bug 3**: `SignalInterrupt()` adds acquire fence to guarantee memory visibility of the `is_running` flag, preventing lost signals Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3063 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Co-authored-by: MrPurple666 <antoniosacramento666usa@gmail.com> Co-committed-by: MrPurple666 <antoniosacramento666usa@gmail.com>
This commit is contained in:
parent
1b1e186a58
commit
e3c942b209
1 changed files with 21 additions and 6 deletions
|
|
@ -371,10 +371,12 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
|
||||||
// Add break loop condition.
|
// Add break loop condition.
|
||||||
m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
|
m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
|
||||||
|
|
||||||
// Lock the thread context.
|
|
||||||
auto* params = &thread->GetNativeExecutionParameters();
|
auto* params = &thread->GetNativeExecutionParameters();
|
||||||
LockThreadParameters(params);
|
LockThreadParameters(params);
|
||||||
|
|
||||||
|
// Ensure visibility of is_running after lock acquire
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
|
||||||
if (params->is_running) {
|
if (params->is_running) {
|
||||||
// We should signal to the running thread.
|
// We should signal to the running thread.
|
||||||
// The running thread will unlock the thread context.
|
// The running thread will unlock the thread context.
|
||||||
|
|
@ -389,15 +391,28 @@ const std::size_t CACHE_PAGE_SIZE = 4096;
|
||||||
|
|
||||||
void ArmNce::ClearInstructionCache() {
|
void ArmNce::ClearInstructionCache() {
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
// Ensure all previous memory operations complete
|
// Use IC IALLU to actually invalidate L1 instruction cache
|
||||||
asm volatile("dmb ish" ::: "memory");
|
asm volatile("dsb ish\n"
|
||||||
asm volatile("dsb ish" ::: "memory");
|
"ic iallu\n"
|
||||||
asm volatile("isb" ::: "memory");
|
"dsb ish\n"
|
||||||
|
"isb" ::: "memory");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) {
|
void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) {
|
||||||
this->ClearInstructionCache();
|
#ifdef ARCHITECTURE_arm64
|
||||||
|
// Invalidate instruction cache for specific range instead of full flush
|
||||||
|
constexpr u64 cache_line_size = 64;
|
||||||
|
const u64 aligned_addr = addr & ~(cache_line_size - 1);
|
||||||
|
const u64 end_addr = (addr + size + cache_line_size - 1) & ~(cache_line_size - 1);
|
||||||
|
|
||||||
|
asm volatile("dsb ish" ::: "memory");
|
||||||
|
for (u64 i = aligned_addr; i < end_addr; i += cache_line_size) {
|
||||||
|
asm volatile("ic ivau, %0" :: "r"(i) : "memory");
|
||||||
|
}
|
||||||
|
asm volatile("dsb ish\n"
|
||||||
|
"isb" ::: "memory");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue