From c78d2068e1fff6b2ba1fd91209d7d5d2b7c2733d Mon Sep 17 00:00:00 2001 From: Exverge Date: Sun, 5 Jul 2026 23:05:20 -0400 Subject: [PATCH] [core/arm] initial fastmem/nce support on variable page sizes & macOS --- CMakeLists.txt | 2 +- .../cmake-modules/DetectArchitecture.cmake | 4 +- src/common/assert.cpp | 4 +- src/common/assert.h | 4 +- src/common/host_memory.cpp | 115 ++++++++++++++---- src/common/host_memory.h | 13 ++ src/common/settings.cpp | 8 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 +- src/core/arm/nce/arm_nce.cpp | 95 +++++++-------- src/core/arm/nce/arm_nce.s | 88 ++++++++------ src/core/arm/nce/arm_nce_asm_definitions.h | 7 ++ src/core/arm/nce/guest_context.h | 92 ++++++++++++++ src/core/arm/nce/interpreter_visitor.cpp | 12 +- src/core/arm/nce/interpreter_visitor.h | 6 +- src/core/arm/nce/patcher.cpp | 6 +- src/core/hle/kernel/k_memory_manager.cpp | 5 + src/core/hle/kernel/svc/svc_debug_string.cpp | 2 +- src/core/hle/service/jit/jit_context.cpp | 7 +- .../loader/deconstructed_rom_directory.cpp | 2 +- src/core/loader/kip.cpp | 2 +- src/core/loader/nro.cpp | 2 +- 22 files changed, 338 insertions(+), 146 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00a3b39281..e664e8a2a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,7 +300,7 @@ if (NOT EXISTS ${PROJECT_BINARY_DIR}/${compat_json}) file(WRITE ${PROJECT_BINARY_DIR}/${compat_json} "") endif() -if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX)) +if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX OR APPLE)) set(HAS_NCE 1) add_compile_definitions(HAS_NCE=1) endif() diff --git a/externals/cmake-modules/DetectArchitecture.cmake b/externals/cmake-modules/DetectArchitecture.cmake index 105963c8c2..6b690330e8 100644 --- a/externals/cmake-modules/DetectArchitecture.cmake +++ b/externals/cmake-modules/DetectArchitecture.cmake @@ -40,8 +40,8 @@ if (CMAKE_OSX_ARCHITECTURES) set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}") # hope and pray the architecture names match - foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES}) - set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE) + foreach(ARCH ${CMAKE_OSX_ARCHITECTURES}) + set(ARCHITECTURE_${ARCH} 1) add_definitions(-DARCHITECTURE_${ARCH}=1) endforeach() diff --git a/src/common/assert.cpp b/src/common/assert.cpp index b0ddc89037..4c8f57882b 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp @@ -22,9 +22,9 @@ void AssertFailSoftImpl() { # elif defined(ARCHITECTURE_arm64) __asm__ __volatile__("brk #0"); # else - exit(1); + __builtin_debugtrap(); # endif -#else // POSIX ^^^ _MSC_VER vvv +#else // Clang/GCC ^^^ MSVC vvv DebugBreak(); #endif } diff --git a/src/common/assert.h b/src/common/assert.h index 298af3071a..7da6641c55 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -17,8 +17,8 @@ void AssertFailSoftImpl(); [[noreturn]] void AssertFatalImpl(); // Prevents errors on old GCC... smh... -#ifdef _MSC_VER -#define YUZU_NO_INLINE __declspec(noinline) +#if defined(_MSC_VER) || defined(__clang__) +#define YUZU_NO_INLINE #else #define YUZU_NO_INLINE __attribute__((noinline)) #endif diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 445d34c444..fd4ceca79f 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -26,10 +26,8 @@ #if defined(__linux__) #include #elif defined(__APPLE__) -#include -#include -#include #include +#include #elif defined(__FreeBSD__) #include #elif defined(__OPENORBIS__) @@ -59,6 +57,7 @@ #include "common/free_region_manager.h" #include "common/host_memory.h" #include "common/logging.h" +#include "common/settings.h" #if defined(__ANDROID__) && __ANDROID_API__ < 30 #include @@ -72,9 +71,6 @@ static int memfd_create(const char* name, unsigned int flags) { namespace Common { -[[maybe_unused]] constexpr size_t PageAlignment = 0x1000; -[[maybe_unused]] constexpr size_t HugePageSize = 0x200000; - #ifdef _WIN32 // Manually imported for MinGW compatibility @@ -401,6 +397,7 @@ private: #ifdef ARCHITECTURE_arm64 +#ifndef __APPLE__ static void* ChooseVirtualBase(size_t virtual_size) { constexpr uintptr_t Map39BitSize = (1ULL << 39); constexpr uintptr_t Map36BitSize = (1ULL << 36); @@ -420,10 +417,9 @@ static void* ChooseVirtualBase(size_t virtual_size) { uintptr_t hint_address = ((rng() % range) + lower) * HugePageSize; // Try to map. - // Note: we may be able to take advantage of MAP_FIXED_NOREPLACE here. void* map_pointer = mmap(reinterpret_cast(hint_address), virtual_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0); // If we successfully mapped, we're done. if (reinterpret_cast(map_pointer) == hint_address) { @@ -441,6 +437,56 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else +static void* ChooseVirtualBase(size_t virtual_size) { + virtual_size -= HugePageSize; // we handle alignment on our own + + // todo: does this have to be 39bit? why? + size_t cursor = 0; + while (cursor < MACH_VM_MAX_ADDRESS - virtual_size) { + u64 region = cursor; + u64 region_size = 0; + + // variables we don't need but apple forces us to use anyway + u32 info_count = VM_REGION_BASIC_INFO_COUNT_64; + vm_region_basic_info_data_64_t info; + mach_port_t name; + + + // find the next mapped region of memory + int res = mach_vm_region(mach_task_self(), ®ion, ®ion_size, VM_REGION_BASIC_INFO_64, + reinterpret_cast(&info), &info_count, &name); + + // the rest of the address space is unmapped, we can just allocate here + if (res == KERN_INVALID_ADDRESS) { + return mmap(reinterpret_cast(cursor), virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + } + if (res != KERN_SUCCESS) { + LOG_WARNING(HW_Memory, "Failed to check memory region: {} {}", mach_error_string(res), res); + continue; + } + + // AlignUp landed in another region, continue from here + if (region <= cursor) { + cursor = AlignUp(region + region_size, HugePageSize); + continue; + } + + // find the difference between this region and the last region, if it's >= virtual_size, we can use it + if (region - cursor >= virtual_size && cursor != 0) { + auto ptr = mmap(reinterpret_cast(cursor), virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (ptr != MAP_FAILED) { + return ptr; + } + } + + cursor = AlignUp(region + region_size, HugePageSize); + } + + return MAP_FAILED; +} +#endif // !defined(__APPLE__) +#else + static void* ChooseVirtualBase(size_t virtual_size) { #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); @@ -450,7 +496,7 @@ static void* ChooseVirtualBase(size_t virtual_size) { return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); } -#endif +#endif // ARCHITECTURE_arm64 #if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__) /// Most Unices don't have a portable shm_open (AIX, OpenBSD, NetBSD, Solaris 11, OpenIndiana) @@ -507,8 +553,6 @@ public: {} bool Init() { - long page_size = sysconf(_SC_PAGESIZE); - ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", page_size); // Backing memory initialization #if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__) fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); @@ -553,7 +597,6 @@ public: LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); return false; } - // Virtual memory initialization virtual_base = virtual_map_base = static_cast(ChooseVirtualBase(virtual_size)); if (virtual_base == MAP_FAILED) { @@ -697,12 +740,13 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) #else // Try to allocate a fastmem arena. // The implementation will fail with std::bad_alloc on errors. - impl = std::make_unique(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize); + impl = std::make_unique(AlignUp(backing_size, HostPageSize), AlignUp(virtual_size, HostPageSize) + HugePageSize); if (impl->Init()) { backing_base = impl->backing_base; virtual_base = impl->virtual_base; if (virtual_base) { // Ensure the virtual base is aligned to the L2 block size. + // TODO: move this to ChooseVirtualBase and drop virtual_base_offset virtual_base = reinterpret_cast(Common::AlignUp(uintptr_t(virtual_base), HugePageSize)); virtual_base_offset = virtual_base - impl->virtual_base; } @@ -724,9 +768,24 @@ HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms, bool separate_heap) { #if !(defined(__OPENORBIS__) || defined(__managarm__)) - ASSERT(virtual_offset % PageAlignment == 0); - ASSERT(host_offset % PageAlignment == 0); - ASSERT(length % PageAlignment == 0); + size_t aligned_length = length; + ASSERT(virtual_offset % HostPageSize == host_offset % HostPageSize); + // todo: placeholder for now, our best bet is probably using the whole pa page for it + if (virtual_offset % HostPageSize != 0) { + // todo: use most permissive protections? or leave to Protect + LOG_WARNING(HW_Memory, "Memory address is unaligned to virtual base, surrounding pages will inherit the same permissions", HostPageSize); + auto aligned = AlignDown(virtual_offset, HostPageSize); + auto diff = virtual_offset - aligned; + assert(virtual_offset > aligned); + virtual_offset = aligned; + aligned_length = AlignUp(length + diff, HostPageSize); + ASSERT(aligned_length >= length); + } + length = aligned_length; + + ASSERT(virtual_offset % HostPageSize == 0); + ASSERT(host_offset % HostPageSize == 0); + ASSERT(length % HostPageSize == 0); ASSERT(virtual_offset + length <= virtual_size); ASSERT(host_offset + length <= backing_size); if (length == 0 || !virtual_base || !impl) { @@ -738,8 +797,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, M void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { #if !(defined(__OPENORBIS__) || defined(__managarm__)) - ASSERT(virtual_offset % PageAlignment == 0); - ASSERT(length % PageAlignment == 0); + ASSERT(virtual_offset % HostPageSize == 0); + ASSERT(length % HostPageSize == 0); ASSERT(virtual_offset + length <= virtual_size); if (length == 0 || !virtual_base || !impl) { return; @@ -750,15 +809,25 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) { #if !(defined(__OPENORBIS__) || defined(__managarm__)) - ASSERT(virtual_offset % PageAlignment == 0); - ASSERT(length % PageAlignment == 0); + bool read = True(perm & MemoryPermission::Read); + bool write = True(perm & MemoryPermission::Write); + bool execute = True(perm & MemoryPermission::Execute); + + if (length % HostPageSize != 0 || virtual_offset % HostPageSize != 0) { + // todo: make this actually inherit most permissive + LOG_WARNING(HW_Memory, "Memory is unaligned to page size, surrounding pages will inherit most permissive permissions"); + auto aligned = AlignDown(virtual_offset, HostPageSize); + auto diff = virtual_offset - aligned; + virtual_offset = aligned; + length = AlignUp(length + diff, HostPageSize); + } + ASSERT(!(read && write && execute)); + ASSERT(virtual_offset % HostPageSize == 0); + ASSERT(length % HostPageSize == 0); ASSERT(virtual_offset + length <= virtual_size); if (length == 0 || !virtual_base || !impl) { return; } - const bool read = True(perm & MemoryPermission::Read); - const bool write = True(perm & MemoryPermission::Write); - const bool execute = True(perm & MemoryPermission::Execute); impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); #endif } diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 24f4670732..ee25539f59 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -8,12 +8,25 @@ #include #include + +#ifndef _MSC_VER +#include +#endif + #include "common/common_funcs.h" #include "common/common_types.h" #include "common/virtual_buffer.h" namespace Common { +#ifndef _MSC_VER +const size_t HostPageSize = sysconf(_SC_PAGESIZE); +#else +constexpr size_t HostPageSize = 0x1000; +#endif +const size_t GuestHostAlignment = HostPageSize / 4096; +constexpr size_t HugePageSize = 0x200000; + enum class MemoryPermission : u32 { Read = 1 << 0, Write = 1 << 1, diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 9b582f1c2a..0c83a7f25d 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -177,15 +177,11 @@ bool IsDMALevelSafe() { } bool IsFastmemEnabled() { - if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging) + if (values.cpu_accuracy.GetValue() == CpuAccuracy::Debugging) return bool(values.cpuopt_fastmem); else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe) return bool(values.cpuopt_unsafe_host_mmu); -#if defined(__linux__) && defined(ARCHITECTURE_arm64) - // Only 4kb systems support host MMU right now - // TODO: Support this - return getpagesize() == 4096; -#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) +#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) return false; #else return true; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index e434a31d5d..724ec26570 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -42,12 +42,12 @@ u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) { std::optional DynarmicCallbacks32::MemoryReadCode(u32 vaddr) { if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) return std::nullopt; - auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK; + auto const aligned_vaddr = vaddr & ~(Dynarmic::CODE_PAGE_SIZE - 1); if (last_code_addr != aligned_vaddr) { m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page)); last_code_addr = aligned_vaddr; } - return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; + return cached_code_page.inst[(vaddr & (Dynarmic::CODE_PAGE_SIZE - 1)) / sizeof(u32)]; } void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) { diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index e6c7e61265..8760e5b1cb 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -45,12 +45,12 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) { std::optional DynarmicCallbacks64::MemoryReadCode(u64 vaddr) { if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) return std::nullopt; - auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK; + auto const aligned_vaddr = vaddr & ~(Dynarmic::CODE_PAGE_SIZE - 1); if (last_code_addr != aligned_vaddr) { m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page)); last_code_addr = aligned_vaddr; } - return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; + return cached_code_page.inst[(vaddr & (Dynarmic::CODE_PAGE_SIZE - 1)) / sizeof(u32)]; } void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) { diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 63d5638fce..3356e26c9b 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -16,9 +16,7 @@ #include "core/hle/kernel/k_process.h" -#include #include -#include namespace Core { @@ -33,14 +31,6 @@ static_assert(offsetof(NativeExecutionParameters, native_context) == TpidrEl0Nat static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock); static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic); -fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) { - _aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx.__reserved); - while (header->magic != FPSIMD_MAGIC) { - header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast(header) + header->size); - } - return reinterpret_cast(header); -} - using namespace Common::Literals; constexpr u32 StackSize = 128_KiB; @@ -48,32 +38,29 @@ constexpr u32 StackSize = 128_KiB; void* ArmNce::RestoreGuestContext(void* raw_context) { // Retrieve the host context. - auto& host_ctx = static_cast(raw_context)->uc_mcontext; + auto host_ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); // Thread-local parameters will be located in x9. - auto* tpidr = reinterpret_cast(host_ctx.regs[9]); + auto* tpidr = reinterpret_cast(host_ctx.regs()[9]); auto* guest_ctx = static_cast(tpidr->native_context); - // Retrieve the host floating point state. - auto* fpctx = GetFloatingPointState(host_ctx); - // Save host callee-saved registers. - std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &fpctx->vregs[8], + std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &host_ctx.vregs()[8], sizeof(guest_ctx->host_ctx.host_saved_vregs)); - std::memcpy(guest_ctx->host_ctx.host_saved_regs.data(), &host_ctx.regs[19], + std::memcpy(guest_ctx->host_ctx.host_saved_regs.data(), &host_ctx.regs()[19], sizeof(guest_ctx->host_ctx.host_saved_regs)); // Save stack pointer. - guest_ctx->host_ctx.host_sp = host_ctx.sp; + guest_ctx->host_ctx.host_sp = *host_ctx.sp(); // Restore all guest state except tpidr_el0. - host_ctx.sp = guest_ctx->sp; - host_ctx.pc = guest_ctx->pc; - host_ctx.pstate = guest_ctx->pstate; - fpctx->fpcr = guest_ctx->fpcr; - fpctx->fpsr = guest_ctx->fpsr; - std::memcpy(host_ctx.regs, guest_ctx->cpu_registers.data(), sizeof(host_ctx.regs)); - std::memcpy(fpctx->vregs, guest_ctx->vector_registers.data(), sizeof(fpctx->vregs)); + *host_ctx.sp() = guest_ctx->sp; + *host_ctx.pc() = guest_ctx->pc; + *host_ctx.pstate() = guest_ctx->pstate; + *host_ctx.fpcr() = guest_ctx->fpcr; + *host_ctx.fpsr() = guest_ctx->fpsr; + std::memcpy(host_ctx.regs(), guest_ctx->cpu_registers.data(), sizeof(guest_ctx->cpu_registers)); + std::memcpy(host_ctx.vregs(), guest_ctx->vector_registers.data(), sizeof(guest_ctx->vector_registers)); // Return the new thread-local storage pointer. return tpidr; @@ -81,47 +68,44 @@ void* ArmNce::RestoreGuestContext(void* raw_context) { void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { // Retrieve the host context. - auto& host_ctx = static_cast(raw_context)->uc_mcontext; - - // Retrieve the host floating point state. - auto* fpctx = GetFloatingPointState(host_ctx); + auto host_ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); // Save all guest registers except tpidr_el0. - std::memcpy(guest_ctx->cpu_registers.data(), host_ctx.regs, sizeof(host_ctx.regs)); - std::memcpy(guest_ctx->vector_registers.data(), fpctx->vregs, sizeof(fpctx->vregs)); - guest_ctx->fpsr = fpctx->fpsr; - guest_ctx->fpcr = fpctx->fpcr; - guest_ctx->pstate = static_cast(host_ctx.pstate); - guest_ctx->pc = host_ctx.pc; - guest_ctx->sp = host_ctx.sp; + std::memcpy(guest_ctx->cpu_registers.data(), host_ctx.regs(), sizeof(guest_ctx->cpu_registers)); + std::memcpy(guest_ctx->vector_registers.data(), host_ctx.vregs(), sizeof(guest_ctx->vector_registers)); + guest_ctx->fpsr = *host_ctx.fpsr(); + guest_ctx->fpcr = *host_ctx.fpcr(); + guest_ctx->pstate = *host_ctx.pstate(); + guest_ctx->pc = *host_ctx.pc(); + guest_ctx->sp = *host_ctx.sp(); // Restore stack pointer. - host_ctx.sp = guest_ctx->host_ctx.host_sp; + *host_ctx.sp() = guest_ctx->host_ctx.host_sp; // Restore host callee-saved registers. - std::memcpy(&host_ctx.regs[19], guest_ctx->host_ctx.host_saved_regs.data(), + std::memcpy(&host_ctx.regs()[19], guest_ctx->host_ctx.host_saved_regs.data(), sizeof(guest_ctx->host_ctx.host_saved_regs)); - std::memcpy(&fpctx->vregs[8], guest_ctx->host_ctx.host_saved_vregs.data(), + std::memcpy(&host_ctx.vregs()[8], guest_ctx->host_ctx.host_saved_vregs.data(), sizeof(guest_ctx->host_ctx.host_saved_vregs)); // Return from the call on exit by setting pc to x30. - host_ctx.pc = guest_ctx->host_ctx.host_saved_regs[11]; + *host_ctx.pc() = guest_ctx->host_ctx.host_saved_regs[11]; // Clear esr_el1 and return it. - host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0); + host_ctx.regs()[0] = guest_ctx->esr_el1.exchange(0); } bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { - auto& host_ctx = static_cast(raw_context)->uc_mcontext; + auto host_ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); auto* info = static_cast(raw_info); // We can't handle the access, so determine why we crashed. - const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast(info->si_addr); + const bool is_prefetch_abort = *host_ctx.pc() == reinterpret_cast(info->si_addr); // For data aborts, skip the instruction and return to guest code. // This will allow games to continue in many scenarios where they would otherwise crash. if (!is_prefetch_abort) { - host_ctx.pc += 4; + *host_ctx.pc() += 4; return true; } @@ -142,14 +126,13 @@ bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, voi } bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { - auto& host_ctx = static_cast(raw_context)->uc_mcontext; - auto* fpctx = GetFloatingPointState(host_ctx); + auto host_ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); // Match and execute an instruction. - auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); + auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx); if (next_pc) { - host_ctx.pc = *next_pc; + *host_ctx.pc() = *next_pc; return true; } @@ -278,7 +261,11 @@ ArmNce::~ArmNce() = default; void ArmNce::Initialize() { if (m_thread_id == -1) { +#if defined(__linux__) m_thread_id = gettid(); +#else + m_thread_id = pthread_mach_thread_np(pthread_self()); +#endif } // Configure signal stack. @@ -381,14 +368,24 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) { if (params->is_running) { // We should signal to the running thread. // The running thread will unlock the thread context. +#if defined(__linux__) syscall(SYS_tkill, m_thread_id, BreakFromRunCodeSignal); +#elif defined(TARGET_OS_MAC) && defined(__aarch64__) + asm volatile( + "mov x0, %0\n" // m_thread_id + "mov x1, %1\n" // BreakFromRunCodeSignal + "mov x16, #328\n" // syscall code for __pthread_kill + "svc #0x80\n" + :: "r"(static_cast(m_thread_id)), "r"(static_cast(BreakFromRunCodeSignal)) + : "x0", "x1", "x16", "memory", "cc"); +#endif } else { // If the thread is no longer running, we have nothing to do. UnlockThreadParameters(params); } } -[[maybe_unused]] const std::size_t CACHE_PAGE_SIZE = 4096; +[[maybe_unused]] const std::size_t CACHE_PAGE_SIZE = Common::HostPageSize; void ArmNce::ClearInstructionCache() { #ifdef __aarch64__ diff --git a/src/core/arm/nce/arm_nce.s b/src/core/arm/nce/arm_nce.s index c68c059491..2e9af52b52 100644 --- a/src/core/arm/nce/arm_nce.s +++ b/src/core/arm/nce/arm_nce.s @@ -7,12 +7,35 @@ mov reg, #(((val) >> 0x00) & 0xFFFF); \ movk reg, #(((val) >> 0x10) & 0xFFFF), lsl #16 +#ifdef __APPLE__ +#define func(name) _##name + +.macro ASM_FUNCTION_START name + +.text +.align 2 +.global _\name +_\name: + +.endm +#else +#define func(name) name +.macro ASM_FUNCTION_START name + +.section .text.\name, "ax", %progbits +.global \name +.type \name, %function +\name: + +.endm +#endif /* static HaltReason Core::ArmNce::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */ -.section .text._ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits -.global _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm -.type _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function -_ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: +#ifndef __APPLE__ +ASM_FUNCTION_START _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm +#else +ASM_FUNCTION_START _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEy +#endif /* Back up host sp to x3. */ /* Back up host tpidr_el0 to x4. */ mov x3, sp @@ -50,10 +73,7 @@ _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: /* static HaltReason Core::ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */ -.section .text._ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits -.global _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv -.type _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, %function -_ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv: +ASM_FUNCTION_START _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv /* This jumps to the signal handler, which will restore the entire context. */ /* On entry, x0 = thread id, which is already in the right place. */ @@ -61,27 +81,30 @@ _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv: mov x9, x1 /* Set up arguments. */ - mov x8, #(__NR_tkill) + /* On entry, x0 = thread id, which is already in the right place. */ mov x1, #(ReturnToRunCodeByExceptionLevelChangeSignal) /* Tail call the signal handler. */ +#ifndef __APPLE__ + mov x8, #(__NR_tkill) svc #0 +#else + mov x16, #328 + svc #0x80 +#endif /* Block execution from flowing here. */ brk #1000 /* static void Core::ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_ -.type _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function -_ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: +ASM_FUNCTION_START _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_ stp x29, x30, [sp, #-0x10]! mov x29, sp /* Call the context restorer with the raw context. */ mov x0, x2 - bl _ZN4Core6ArmNce19RestoreGuestContextEPv + bl func(_ZN4Core6ArmNce19RestoreGuestContextEPv) /* Save the old value of tpidr_el0. */ mrs x8, tpidr_el0 @@ -92,7 +115,7 @@ _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: msr tpidr_el0, x0 /* Unlock the context. */ - bl _ZN4Core6ArmNce22UnlockThreadParametersEPv + bl func(_ZN4Core6ArmNce22UnlockThreadParametersEPv) /* Returning from here will enter the guest. */ ldp x29, x30, [sp], #0x10 @@ -100,10 +123,7 @@ _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: /* static void Core::ArmNce::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_ -.type _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, %function -_ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_: +ASM_FUNCTION_START _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_ /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -121,7 +141,7 @@ _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_: /* Tail call the restorer. */ mov x1, x2 - b _ZN4Core6ArmNce16SaveGuestContextEPNS_12GuestContextEPv + b func(_ZN4Core6ArmNce16SaveGuestContextEPNS_12GuestContextEPv) /* Returning from here will enter host code. */ @@ -131,10 +151,7 @@ _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_: /* static void Core::ArmNce::GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_ -.type _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, %function -_ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_: +ASM_FUNCTION_START _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_ /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -146,7 +163,7 @@ _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_: /* Incorrect TLS magic, so this is a host fault. */ /* Tail call the handler. */ - b _ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_ + b func(_ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_) 1: /* Correct TLS magic, so this is a guest fault. */ @@ -163,7 +180,7 @@ _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_: msr tpidr_el0, x3 /* Call the handler. */ - bl _ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_ + bl func(_ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_) /* If the handler returned false, we want to preserve the host tpidr_el0. */ cbz x0, 2f @@ -177,10 +194,7 @@ _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_: ret /* static void Core::ArmNce::GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_ -.type _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, %function -_ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_: +ASM_FUNCTION_START _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_ /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -192,7 +206,7 @@ _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_: /* Incorrect TLS magic, so this is a host fault. */ /* Tail call the handler. */ - b _ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_ + b func(_ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_) 1: /* Correct TLS magic, so this is a guest fault. */ @@ -209,7 +223,7 @@ _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_: msr tpidr_el0, x3 /* Call the handler. */ - bl _ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_ + bl func(_ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_) /* If the handler returned false, we want to preserve the host tpidr_el0. */ cbz x0, 2f @@ -224,10 +238,7 @@ _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_: /* static void Core::ArmNce::LockThreadParameters(void* tpidr) */ -.section .text._ZN4Core6ArmNce20LockThreadParametersEPv, "ax", %progbits -.global _ZN4Core6ArmNce20LockThreadParametersEPv -.type _ZN4Core6ArmNce20LockThreadParametersEPv, %function -_ZN4Core6ArmNce20LockThreadParametersEPv: +ASM_FUNCTION_START _ZN4Core6ArmNce20LockThreadParametersEPv /* Offset to lock member. */ add x0, x0, #(TpidrEl0Lock) @@ -252,10 +263,7 @@ _ZN4Core6ArmNce20LockThreadParametersEPv: /* static void Core::ArmNce::UnlockThreadParameters(void* tpidr) */ -.section .text._ZN4Core6ArmNce22UnlockThreadParametersEPv, "ax", %progbits -.global _ZN4Core6ArmNce22UnlockThreadParametersEPv -.type _ZN4Core6ArmNce22UnlockThreadParametersEPv, %function -_ZN4Core6ArmNce22UnlockThreadParametersEPv: +ASM_FUNCTION_START _ZN4Core6ArmNce22UnlockThreadParametersEPv /* Offset to lock member. */ add x0, x0, #(TpidrEl0Lock) diff --git a/src/core/arm/nce/arm_nce_asm_definitions.h b/src/core/arm/nce/arm_nce_asm_definitions.h index 8ea4383f73..c42da22ff1 100644 --- a/src/core/arm/nce/arm_nce_asm_definitions.h +++ b/src/core/arm/nce/arm_nce_asm_definitions.h @@ -5,8 +5,15 @@ #define __ASSEMBLY__ +#ifndef __APPLE__ #include #include +#else +#define SIGUSR2 31 +#define SIGURG 16 +#define SIGSEGV 11 +#define SIGBUS 10 +#endif #define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2 #define BreakFromRunCodeSignal SIGURG diff --git a/src/core/arm/nce/guest_context.h b/src/core/arm/nce/guest_context.h index a7eadccce5..66e13d8186 100644 --- a/src/core/arm/nce/guest_context.h +++ b/src/core/arm/nce/guest_context.h @@ -10,6 +10,9 @@ #include "core/arm/arm_interface.h" #include "core/arm/nce/arm_nce_asm_definitions.h" +#include +#include + namespace Core { class ArmNce; @@ -40,6 +43,90 @@ struct GuestContext { ArmNce* parent{}; }; +class KernelContext { +public: +#if defined(__linux__) + KernelContext(void* ptr_) : ptr(static_cast(ptr_)), fpsimd{GetFloatingPointState(ptr)} {} + + u64* pc() { + // u64 (unsigned long) does not equal unsigned long long + // thank you gcc + return reinterpret_cast(&ptr->pc); + } + + u64* sp() { + return reinterpret_cast(&ptr->sp); + } + + u64* regs() { + return reinterpret_cast(&ptr->regs); + } + + u128* vregs() { + // returns __uint128, u128 is a std::array + return reinterpret_cast(&fpsimd->vregs); + } + + u32* fpcr() { + return &fpsimd->fpcr; + } + + u32* fpsr() { + return &fpsimd->fpsr; + } + + u32* pstate() { + // only first 32 bits are used + return reinterpret_cast(&ptr->pstate); + } + +#elif defined(__APPLE__) + KernelContext(void* ptr) : ptr(static_cast(ptr)) {} + + u64* pc() { + return &(*ptr)->__ss.__pc; + } + + u64* sp() { + return &(*ptr)->__ss.__sp; + } + + u64* regs() { + return (*ptr)->__ss.__x; + } + + u128* vregs() { + // .__v returns __uint128, u128 is an std::array + return reinterpret_cast((*ptr)->__ns.__v); + } + + u32* fpcr() { + return &(*ptr)->__ns.__fpcr; + } + + u32* fpsr() { + return &(*ptr)->__ns.__fpsr; + } + + u32* pstate() { + return &(*ptr)->__ss.__cpsr; + } +#endif +private: + mcontext_t* ptr; +#ifdef __linux__ + fpsimd_context* fpsimd; + + fpsimd_context* GetFloatingPointState(mcontext_t* host_ctx) { + _aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx->__reserved); + while (header->magic != FPSIMD_MAGIC) { + header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast(header) + header->size); + } + return reinterpret_cast(header); + } +#endif +}; + // Verify assembly offsets. static_assert(offsetof(GuestContext, sp) == GuestContextSp); static_assert(offsetof(GuestContext, host_ctx) == GuestContextHostContext); @@ -49,4 +136,9 @@ static_assert(offsetof(HostContext, host_tpidr_el0) == HostContextTpidrEl0); static_assert(offsetof(HostContext, host_saved_regs) == HostContextRegs); static_assert(offsetof(HostContext, host_saved_vregs) == HostContextVregs); +#ifdef TARGET_OS_MAC +// ensure that fp and lr are next to the rest of the x registers so they can be accessed like an array +static_assert(offsetof(_STRUCT_ARM_THREAD_STATE64, __sp) - offsetof(_STRUCT_ARM_THREAD_STATE64, __x) == sizeof(u64) * 31); +#endif + } // namespace Core diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp index 2ccc176323..598122abd7 100644 --- a/src/core/arm/nce/interpreter_visitor.cpp +++ b/src/core/arm/nce/interpreter_visitor.cpp @@ -8,6 +8,8 @@ #include #include "core/arm/nce/interpreter_visitor.h" +#include "guest_context.h" + namespace Core { namespace { @@ -761,11 +763,11 @@ bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3 return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt); } -std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, fpsimd_context* fpsimd_context) { - std::span regs(reinterpret_cast(context->regs), 31); - std::span vregs(reinterpret_cast(fpsimd_context->vregs), 32); - u64& sp = *reinterpret_cast(&context->sp); - const u64& pc = *reinterpret_cast(&context->pc); +std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, KernelContext context) { + std::span regs((context.regs()), 31); + std::span vregs((context.vregs()), 32); + u64& sp = *reinterpret_cast(context.sp()); + const u64& pc = *reinterpret_cast(context.pc()); InterpreterVisitor visitor(memory, regs, vregs, sp, pc); u32 instruction = memory.Read32(pc); diff --git a/src/core/arm/nce/interpreter_visitor.h b/src/core/arm/nce/interpreter_visitor.h index 131b69cd7d..5311fca79c 100644 --- a/src/core/arm/nce/interpreter_visitor.h +++ b/src/core/arm/nce/interpreter_visitor.h @@ -18,8 +18,9 @@ #include "core/arm/nce/visitor_base.h" namespace Core { + class KernelContext; -namespace Memory { + namespace Memory { class Memory; } @@ -105,7 +106,6 @@ private: const u64& m_pc; }; -std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, - fpsimd_context* fpsimd_context); +std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, KernelContext context); } // namespace Core diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index 79ff3b1e31..d793aea940 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp @@ -10,6 +10,8 @@ #include "core/arm/nce/guest_context.h" #include "core/arm/nce/instructions.h" #include "core/arm/nce/patcher.h" + +#include "common/host_memory.h" #include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/svc.h" @@ -356,11 +358,11 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::Co } size_t Patcher::GetSectionSize() const noexcept { - return Common::AlignUp(m_patch_instructions.size() * sizeof(u32), Core::Memory::YUZU_PAGESIZE); + return Common::AlignUp(m_patch_instructions.size() * sizeof(u32), Common::HostPageSize); } size_t Patcher::GetPreSectionSize() const noexcept { - return Common::AlignUp(m_patch_instructions_pre.size() * sizeof(u32), Core::Memory::YUZU_PAGESIZE); + return Common::AlignUp(m_patch_instructions_pre.size() * sizeof(u32), Common::HostPageSize); } void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) { diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index 743e290541..4fe2740c6f 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -212,6 +212,11 @@ KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, siz return 0; } + // todo: find a better way to do this + if (align_pages % Common::GuestHostAlignment != 0) { + align_pages = Common::AlignUp(align_pages, Common::GuestHostAlignment); + } + // Lock the pool that we're allocating from. const auto [pool, dir] = DecodeOption(option); KScopedLightLock lk(m_pool_locks[static_cast(pool)]); diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp index c190fa7a3f..9a3636b1ed 100644 --- a/src/core/hle/kernel/svc/svc_debug_string.cpp +++ b/src/core/hle/kernel/svc/svc_debug_string.cpp @@ -50,7 +50,7 @@ Result OutputDebugString(Core::System& system, u64 address, u64 len) { if (flusher_data.msg_buffer.back() == '\n') flusher_data.msg_buffer.pop_back(); - LOG_INFO(Debug_Emulated, "\n{}", flusher_data.msg_buffer); + LOG_CRITICAL(Debug_Emulated, "\n{}", flusher_data.msg_buffer); flusher_data.msg_buffer.clear(); } if (stop_token.stop_requested()) break; diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index ce51fbd3f5..434f734a44 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp @@ -60,13 +60,14 @@ public: {} std::optional MemoryReadCode(VAddr vaddr) override { - static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE); - auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK; + // todo: does code page have to be 4kib? + //static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE); + auto const aligned_vaddr = vaddr & ~(Dynarmic::CODE_PAGE_SIZE - 1); if (last_code_addr != aligned_vaddr) { cached_code_page = ReadMemory(aligned_vaddr); last_code_addr = aligned_vaddr; } - return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; + return cached_code_page.inst[(vaddr & (Dynarmic::CODE_PAGE_SIZE - 1)) / sizeof(u32)]; } void InstructionSynchronizationBarrierRaised() override { last_code_addr = u64(-1); //reset back, force refetch diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 3286606c5e..b3e92e098d 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -232,7 +232,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect // TODO: this is bad form of ASLR, it sucks std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue() - ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000; + ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xffffff & ~(Common::HostPageSize - 1); // Setup the process code layout if (process.LoadFromMetadata(system.Kernel(), metadata, code_size, fastmem_base, aslr_offset).IsError()) { diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 62bcbc9579..8ff1345a9e 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -90,7 +90,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, // TODO: this is bad form of ASLR, it sucks std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue() - ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000; + ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xffffff & ~(Common::HostPageSize - 1); // Setup the process code layout if (process.LoadFromMetadata(system.Kernel(), FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset).IsError()) { diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 4ba4bde0bb..e20185c927 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -276,7 +276,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process, // TODO: this is bad form of ASLR, it sucks std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue() - ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000; + ? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xffffff & ~(Common::HostPageSize - 1); // Setup the process code layout if (process