From 814260f0b6bb0dd6f9a22155cdf5917849b3db2c Mon Sep 17 00:00:00 2001 From: joevt Date: Sat, 14 Jan 2023 23:39:36 -0800 Subject: [PATCH 1/3] ppcmmu: Reduce unmapped physical memory logging. Don't log consecutive accesses to unmapped physical memory addresses. This saves a couple hundred thousand lines in the log in some cases. This is only a partial fix. Any access that isn't logged should be queued and output if a log message is output that is not this log message or after a time period. --- cpu/ppc/ppcmmu.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 70eda5e..69d9e78 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-21 divingkatae and maximum +Copyright (C) 2018-23 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -620,7 +620,16 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write) } return tlb_entry; } else { - LOG_F(WARNING, "Access to unmapped physical memory, phys_addr=0x%08X", phys_addr); + static uint32_t last_phys_addr = -1; + static uint32_t first_phys_addr = -1; + if (phys_addr != last_phys_addr + 4) { + if (last_phys_addr != -1 && last_phys_addr != first_phys_addr) { + LOG_F(WARNING, " ... phys_addr=0x%08X", last_phys_addr); + } + first_phys_addr = phys_addr; + LOG_F(WARNING, "Access to unmapped physical memory, phys_addr=0x%08X", first_phys_addr); + } + last_phys_addr = phys_addr; return &UnmappedMem; } } From 16123dea45344ba6767ce2512be58dc7819d58b5 Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 14 Jun 2023 21:10:34 -0700 Subject: [PATCH 2/3] ppcmmu: Add 64-bit accesses to I/O Also add an exception for unaligned 64 bit. 64 bit accesses require dword alignment. --- cpu/ppc/ppcmmu.cpp | 110 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 27 deletions(-) diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 69d9e78..b03556a 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -987,9 +987,10 @@ void mmu_print_regs() } // Forward declarations. -static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size); -static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value, - uint32_t size); +template +static T read_unaligned(uint32_t guest_va, uint8_t *host_va); +template +static void write_unaligned(uint32_t guest_va, uint8_t *host_va, T value); template inline T mmu_read_vmem(uint32_t guest_va) @@ -1034,11 +1035,28 @@ inline T mmu_read_vmem(uint32_t guest_va) #ifdef MMU_PROFILING iomem_reads_total++; #endif - return ( - tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, - sizeof(T)) - ); + if (sizeof(T) == 8) { + if (guest_va & 3) { + ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + } + { + return ( + ((T)tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, + guest_va - tlb2_entry->reg_desc->start, + 4) << 32) | + tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, + guest_va + 4 - tlb2_entry->reg_desc->start, + 4) + ); + } + } + else { + return ( + tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, + guest_va - tlb2_entry->reg_desc->start, + sizeof(T)) + ); + } } } @@ -1048,7 +1066,7 @@ inline T mmu_read_vmem(uint32_t guest_va) // handle unaligned memory accesses if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) { - return read_unaligned(guest_va, host_va, sizeof(T)); + return read_unaligned(guest_va, host_va); } // handle aligned memory accesses @@ -1143,9 +1161,24 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) #ifdef MMU_PROFILING iomem_writes_total++; #endif - tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, - value, sizeof(T)); + if (sizeof(T) == 8) { + if (guest_va & 3) { + ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + } + { + tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, + guest_va - tlb2_entry->reg_desc->start, + value >> 32, 4); + tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, + guest_va + 4 - tlb2_entry->reg_desc->start, + (uint32_t)value, 4); + } + } + else { + tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, + guest_va - tlb2_entry->reg_desc->start, + value, sizeof(T)); + } return; } } @@ -1156,7 +1189,7 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) // handle unaligned memory accesses if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) { - write_unaligned(guest_va, host_va, value, sizeof(T)); + write_unaligned(guest_va, host_va, value); return; } @@ -1183,42 +1216,53 @@ template void mmu_write_vmem(uint32_t guest_va, uint16_t value); template void mmu_write_vmem(uint32_t guest_va, uint32_t value); template void mmu_write_vmem(uint32_t guest_va, uint64_t value); -static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size) +template +static T read_unaligned(uint32_t guest_va, uint8_t *host_va) { - uint32_t result = 0; + T result = 0; // is it a misaligned cross-page read? - if (((guest_va & 0xFFF) + size) > 0x1000) { + if (((guest_va & 0xFFF) + sizeof(T)) > 0x1000) { #ifdef MMU_PROFILING unaligned_crossp_r++; #endif // Break such a memory access into multiple, bytewise accesses. // Because such accesses suffer a performance penalty, they will be // presumably very rare so don't waste time optimizing the code below. - for (int i = 0; i < size; guest_va++, i++) { + for (int i = 0; i < sizeof(T); guest_va++, i++) { result = (result << 8) | mmu_read_vmem(guest_va); } } else { #ifdef MMU_PROFILING unaligned_reads++; #endif - switch(size) { + switch(sizeof(T)) { + case 1: + return *host_va; case 2: return READ_WORD_BE_U(host_va); case 4: return READ_DWORD_BE_U(host_va); - case 8: // FIXME: should we raise alignment exception here? + case 8: + if (guest_va & 3) { + ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + } return READ_QWORD_BE_U(host_va); } } return result; } -static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value, - uint32_t size) +// explicitely instantiate all required read_unaligned variants +template uint16_t read_unaligned(uint32_t guest_va, uint8_t *host_va); +template uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va); +template uint64_t read_unaligned(uint32_t guest_va, uint8_t *host_va); + +template +static void write_unaligned(uint32_t guest_va, uint8_t *host_va, T value) { // is it a misaligned cross-page write? - if (((guest_va & 0xFFF) + size) > 0x1000) { + if (((guest_va & 0xFFF) + sizeof(T)) > 0x1000) { #ifdef MMU_PROFILING unaligned_crossp_w++; #endif @@ -1226,29 +1270,41 @@ static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value, // Because such accesses suffer a performance penalty, they will be // presumably very rare so don't waste time optimizing the code below. - uint32_t shift = (size - 1) * 8; + uint32_t shift = (sizeof(T) - 1) * 8; - for (int i = 0; i < size; shift -= 8, guest_va++, i++) { + for (int i = 0; i < sizeof(T); shift -= 8, guest_va++, i++) { mmu_write_vmem(guest_va, (value >> shift) & 0xFF); } } else { #ifdef MMU_PROFILING unaligned_writes++; #endif - switch(size) { + switch(sizeof(T)) { + case 1: + *host_va = value; + break; case 2: WRITE_WORD_BE_U(host_va, value); break; case 4: WRITE_DWORD_BE_U(host_va, value); break; - case 8: // FIXME: should we raise alignment exception here? + case 8: + if (guest_va & 3) { + ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x0); + } WRITE_QWORD_BE_U(host_va, value); break; } } } +// explicitely instantiate all required write_unaligned variants +template void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint16_t value); +template void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value); +template void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint64_t value); + + /* MMU profiling. */ #ifdef MMU_PROFILING @@ -1877,7 +1933,7 @@ uint8_t* quickinstruction_translate(uint32_t addr) { return real_addr; } -#endif +#endif // Old and slow code uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size) { uint32_t save_dsisr, save_dar; From ac64f9e30d3728e1b3ee5b56024321b5169d2184 Mon Sep 17 00:00:00 2001 From: joevt Date: Sun, 23 Jul 2023 03:42:40 -0700 Subject: [PATCH 3/3] ppcmmu: Fix mmio read/write offset calculation. For TLBs referencing an mmio region, calculate an offset that will translate a guest virtual address to an offset in the mmio region. --- cpu/ppc/ppcmmu.cpp | 15 ++++++++------- cpu/ppc/ppcmmu.h | 12 ++++++++---- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index b03556a..9199f40 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -607,6 +607,7 @@ static TLBEntry* dtlb2_refill(uint32_t guest_va, int is_write) if (reg_desc->type & RT_MMIO) { // MMIO region tlb_entry->flags = flags | TLBFlags::PAGE_IO; tlb_entry->reg_desc = reg_desc; + tlb_entry->reg_va_offs = (phys_addr - reg_desc->start) - guest_va; } else { // memory region backed by host memory tlb_entry->flags = flags | TLBFlags::PAGE_MEM; tlb_entry->host_va_offs_r = (int64_t)reg_desc->mem_ptr - guest_va + @@ -1042,10 +1043,10 @@ inline T mmu_read_vmem(uint32_t guest_va) { return ( ((T)tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va), 4) << 32) | tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, - guest_va + 4 - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va) + 4, 4) ); } @@ -1053,7 +1054,7 @@ inline T mmu_read_vmem(uint32_t guest_va) else { return ( tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va), sizeof(T)) ); } @@ -1167,16 +1168,16 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) } { tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va), value >> 32, 4); tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, - guest_va + 4 - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va) + 4, (uint32_t)value, 4); } } else { tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start, - guest_va - tlb2_entry->reg_desc->start, + static_cast(tlb2_entry->reg_va_offs + guest_va), value, sizeof(T)); } return; @@ -1686,7 +1687,7 @@ static inline uint64_t tlb_translate_addr(uint32_t guest_va) tlb1_entry->host_va_offs_r = tlb2_entry->host_va_offs_r; return tlb1_entry->host_va_offs_r + guest_va; } else { // an attempt to access a memory-mapped device - return guest_va - tlb2_entry->reg_desc->start; + return tlb2_entry->reg_va_offs + guest_va; } } } diff --git a/cpu/ppc/ppcmmu.h b/cpu/ppc/ppcmmu.h index 914a9b7..9f270e4 100644 --- a/cpu/ppc/ppcmmu.h +++ b/cpu/ppc/ppcmmu.h @@ -82,11 +82,15 @@ typedef struct TLBEntry { uint16_t flags; uint16_t lru_bits; union { - int64_t host_va_offs_r; - AddressMapEntry* reg_desc; + struct { + int64_t host_va_offs_r; + int64_t host_va_offs_w; + }; + struct { + AddressMapEntry* reg_desc; + int64_t reg_va_offs; + }; }; - int64_t host_va_offs_w; - int64_t unused; } TLBEntry; enum TLBFlags : uint16_t {