summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/arm/nce/arm_nce.cpp124
1 files changed, 63 insertions, 61 deletions
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<u64>(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;
+ }
+ }
+
+ // 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
+ }
- // Find replacement entry using enhanced replacement policy
- const size_t replace_idx = FindReplacementEntry(set_start);
+ // 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<u64>::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<u32>::max()) {
- entry.access_count++;
- }
-}
-
void ArmNce::InvalidateTlb() {
std::lock_guard lock(m_tlb_mutex);
for (auto& entry : m_tlb) {