diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 567da5838..491edd9f9 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -144,15 +144,22 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, auto* fpctx = GetFloatingPointState(host_ctx); auto& memory = guest_ctx->system->ApplicationMemory(); - // Match and execute an instruction. + // Log the alignment fault for debugging + LOG_DEBUG(Core_ARM, "Alignment fault at PC={:X}", host_ctx.pc); + + // Try to handle the instruction auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); if (next_pc) { host_ctx.pc = *next_pc; return true; } - // We couldn't handle the access. - return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); + // If we couldn't handle it, try to skip the instruction as a fallback + LOG_DEBUG(Core_ARM, "Could not handle alignment fault, skipping instruction"); + host_ctx.pc += 4; // Skip to next instruction + + // Return true to continue execution + return true; } bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { @@ -163,24 +170,27 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi // Get the ArmNce instance from the guest context ArmNce* nce = guest_ctx->parent; - // Check TLB first with proper synchronization + // Check TLB first if (TlbEntry* entry = nce->FindTlbEntry(fault_addr)) { if (!entry->writable && info->si_code == SEGV_ACCERR) { + LOG_DEBUG(Core_ARM, "Write to read-only memory at {:X}", fault_addr); return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); } return true; } - // TLB miss handling + // TLB miss handling with better error checking if (memory.InvalidateNCE(fault_addr, Memory::CITRON_PAGESIZE)) { - // Get the host address directly since GetHostAddressInfo isn't available const u64 host_addr = reinterpret_cast(memory.GetPointer(fault_addr)); - const bool writable = true; // Default to writable for now if (host_addr) { - nce->AddTlbEntry(fault_addr, host_addr, Memory::CITRON_PAGESIZE, writable); + nce->AddTlbEntry(fault_addr, host_addr, Memory::CITRON_PAGESIZE, true); return true; + } else { + LOG_DEBUG(Core_ARM, "Failed to get host address for guest address {:X}", fault_addr); } + } else { + LOG_DEBUG(Core_ARM, "Memory invalidation failed for address {:X}", fault_addr); } return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); @@ -396,15 +406,17 @@ void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) { TlbEntry* ArmNce::FindTlbEntry(u64 guest_addr) { std::lock_guard lock(m_tlb_mutex); - const size_t set_index = GetTlbSetIndex(guest_addr); - const size_t set_start = set_index * TLB_WAYS; - - for (size_t i = 0; i < TLB_WAYS; i++) { - TlbEntry& entry = m_tlb[set_start + i]; + // Simple linear search - more reliable than complex indexing + for (size_t i = 0; i < TLB_SIZE; i++) { + TlbEntry& entry = m_tlb[i]; if (entry.valid && guest_addr >= entry.guest_addr && guest_addr < (entry.guest_addr + entry.size)) { - UpdateTlbEntryStats(entry); + + // Simple access tracking - just increment counter + if (entry.access_count < 1000) { // Prevent overflow + entry.access_count++; + } return &entry; } } @@ -412,65 +424,55 @@ TlbEntry* ArmNce::FindTlbEntry(u64 guest_addr) { } void ArmNce::AddTlbEntry(u64 guest_addr, u64 host_addr, u32 size, bool writable) { + // Validate addresses before proceeding + if (!host_addr) { + LOG_ERROR(Core_ARM, "Invalid host address for guest address {:X}", guest_addr); + return; + } + std::lock_guard lock(m_tlb_mutex); - const size_t set_index = GetTlbSetIndex(guest_addr); - const size_t set_start = set_index * TLB_WAYS; + // First try to find an invalid entry + size_t replace_idx = TLB_SIZE; + for (size_t i = 0; i < TLB_SIZE; i++) { + if (!m_tlb[i].valid) { + replace_idx = i; + break; + } + } - // Find replacement entry using enhanced replacement policy - const size_t replace_idx = FindReplacementEntry(set_start); + // If no invalid entries, use simple LRU + if (replace_idx == TLB_SIZE) { + u32 lowest_count = UINT32_MAX; + for (size_t i = 0; i < TLB_SIZE; i++) { + if (m_tlb[i].access_count < lowest_count) { + lowest_count = m_tlb[i].access_count; + replace_idx = i; + } + } + } + + // Safety check + if (replace_idx >= TLB_SIZE) { + replace_idx = 0; // Fallback to first entry if something went wrong + } + + // Page align the addresses for consistency + const u64 page_mask = size - 1; + const u64 aligned_guest = guest_addr & ~page_mask; + const u64 aligned_host = host_addr & ~page_mask; m_tlb[replace_idx] = { - .guest_addr = guest_addr & ~(size - 1), - .host_addr = host_addr & ~(size - 1), + .guest_addr = aligned_guest, + .host_addr = aligned_host, .size = size, .valid = true, .writable = writable, - .last_access_time = ++m_tlb_access_counter, + .last_access_time = 0, // Not used in simplified implementation .access_count = 1 }; } -size_t ArmNce::GetTlbSetIndex(u64 guest_addr) const { - // Improved set index calculation to reduce conflicts - return ((guest_addr >> 12) ^ (guest_addr >> 18)) % TLB_SETS; -} - -size_t ArmNce::FindReplacementEntry(size_t set_start) { - u64 oldest_access = std::numeric_limits::max(); - size_t replace_idx = set_start; - - // Find invalid entry first - for (size_t i = 0; i < TLB_WAYS; i++) { - const size_t idx = set_start + i; - if (!m_tlb[idx].valid) { - return idx; - } - } - - // Otherwise use LRU with access frequency consideration - for (size_t i = 0; i < TLB_WAYS; i++) { - const size_t idx = set_start + i; - const TlbEntry& entry = m_tlb[idx]; - - // Factor in both access time and frequency - u64 weight = entry.last_access_time + (entry.access_count << 8); - if (weight < oldest_access) { - oldest_access = weight; - replace_idx = idx; - } - } - - return replace_idx; -} - -void ArmNce::UpdateTlbEntryStats(TlbEntry& entry) { - entry.last_access_time = ++m_tlb_access_counter; - if (entry.access_count < std::numeric_limits::max()) { - entry.access_count++; - } -} - void ArmNce::InvalidateTlb() { std::lock_guard lock(m_tlb_mutex); for (auto& entry : m_tlb) {