diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 0155471111..55cb945449 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -3,6 +3,19 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#ifdef __aarch64__ + +// short asm ops should always be inlined +#if !defined(__clang__) && !defined(__GNUC__) +#define ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) +// todo: windows support?? it supports native context switching and signal handling +// https://learn.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler +// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadcontext +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif #include #include @@ -29,15 +42,113 @@ struct sigaction g_orig_segv_action; // Verify assembly offsets. using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters; -static_assert(offsetof(NativeExecutionParameters, native_context) == TpidrEl0NativeContext); -static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock); -static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic); using namespace Common::Literals; constexpr u32 StackSize = 128_KiB; } // namespace +ALWAYS_INLINE +void* ArmNce::GetGuestParameters() { + void* nep; /* NativeExecutionParameters* */ +#ifdef __APPLE__ + // https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/libsyscall/os/tsd.h#L156-L189 + asm volatile( + "mrs %[out], TPIDRRO_EL0\n" + "ldr %[out], [ %[out], #%[off] ]\n" + : [out] "=&r"(nep) + : [off] "i"(CONTEXT_KEY * 8) + : "memory"); +#else + asm volatile( + "mrs %0, TPIDR_EL0\n" + : "=r"(nep)); +#endif + return nep; +} + +void ArmNce::LockThreadParameters(void* tpidr) { + +} + +void ArmNce::UnlockThreadParameters(void* tpidr) { + +} + +void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_context) { + DEBUG_ASSERT(sig == SIGSEGV); + + NativeExecutionParameters* nep = static_cast(GetGuestParameters()); + +#ifdef __APPLE__ + if (nep->is_actually_running) { +#else + if (nep->magic == Common::MakeMagic('Y', 'U', 'Z', 'U')) { + // Load the host's TPIDR_EL0 value + u64 scratch; + asm volatile( + "ldr %[scratch], [ %[tpidr], #[off] ]\n" + "msr TPIDR_EL0, %[scratch]\n" + : [scratch] "=&r"(scratch), + : [tpidr] "r"(nep), + : "memory" + ); +#endif + + auto* info = static_cast(raw_info); + auto* guest_ctx = static_cast(nep->native_context); + auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); + + if (sig == SIGSEGV) { + // Try to handle an invalid access. + // TODO: handle accesses which split a page? + const Common::ProcessAddress addr = + (reinterpret_cast(info->si_addr) & ~Memory::YUZU_PAGEMASK); + if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) { + // We handled the access successfully and are returning to guest code. + goto ret; + } + } else if (sig == SIGBUS) { + // Match and execute an instruction. + auto ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); + auto next_pc = MatchAndExecuteOneInstruction(memory, &ctx); + if (next_pc) { + // We handled the access successfully and are returning to guest code. + *ctx.pc() = *next_pc; + goto ret; + } + } else [[unlikely]] { + UNREACHABLE_MSG("unexpected signal {}", sig); + } + + // We couldn't handle the access. + if (HandleFailedGuestFault(guest_ctx, raw_info, raw_context)) { + // Return to guest + goto ret; + } + // Otherwise HandleFailedGuestFault sets host context and returns to host + return; + + ret: +#ifndef __APPLE__ + asm volatile( + "msr TPIDR_EL0, %0\n" + :: "r"(nep)); +#else + (void)0; +#endif + } else { + // Host fault, call original handler + if (sig == SIGSEGV) { + g_orig_segv_action.sa_sigaction(sig, static_cast(raw_info), raw_context); + } else if (sig == SIGBUS) { + g_orig_bus_action.sa_sigaction(sig, static_cast(raw_info), raw_context); + } else [[unlikely]] { + UNREACHABLE_MSG("unexpected signal {}", sig); + } + } +} + void* ArmNce::RestoreGuestContext(void* raw_context) { // Retrieve the host context. auto host_ctx = KernelContext(&static_cast(raw_context)->uc_mcontext); @@ -127,46 +238,6 @@ bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, voi return false; } -bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { - 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); - if (next_pc) { - *host_ctx.pc() = *next_pc; - return true; - } - - // We couldn't handle the access. - return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); -} - -bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { - auto* info = static_cast(raw_info); - - // Try to handle an invalid access. - // TODO: handle accesses which split a page? - const Common::ProcessAddress addr = - (reinterpret_cast(info->si_addr) & ~Memory::YUZU_PAGEMASK); - auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); - if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) { - // We handled the access successfully and are returning to guest code. - return true; - } - - // We couldn't handle the access. - return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); -} - -void ArmNce::HandleHostAlignmentFault(int sig, void* raw_info, void* raw_context) { - return g_orig_bus_action.sa_sigaction(sig, static_cast(raw_info), raw_context); -} - -void ArmNce::HandleHostAccessFault(int sig, void* raw_info, void* raw_context) { - return g_orig_segv_action.sa_sigaction(sig, static_cast(raw_info), raw_context); -} - void ArmNce::LockThread(Kernel::KThread* thread) { auto* thread_params = &thread->GetNativeExecutionParameters(); LockThreadParameters(thread_params); @@ -261,7 +332,19 @@ ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index) ArmNce::~ArmNce() = default; +#ifdef __APPLE__ +// https://github.com/apple-oss-distributions/libpthread/blob/42d026df5b07825070f60134b980a1ec2552dfee/src/pthread_tsd.c#L418-L435 +extern "C" int pthread_key_init_np(int, void (*)(void *)); +#endif + void ArmNce::Initialize() { +#ifdef __APPLE__ + if (m_thread_id == -1) { + m_thread_id = pthread_mach_thread_np(pthread_self()); + } + + ASSERT(pthread_key_init_np(CONTEXT_KEY, [](void*) -> void {}) == 0); +#endif if (m_thread_id == -1) { #if defined(__linux__) m_thread_id = gettid(); @@ -317,7 +400,7 @@ void ArmNce::Initialize() { struct sigaction access_fault_action {}; access_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; access_fault_action.sa_sigaction = - reinterpret_cast(&ArmNce::GuestAccessFaultSignalHandler); + reinterpret_cast(&ArmNce::GuestMemoryFaultSignalHandler); access_fault_action.sa_mask = signal_mask; Common::SigAction(GuestAccessFaultSignal, &access_fault_action, &g_orig_segv_action); }); @@ -372,7 +455,7 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) { // The running thread will unlock the thread context. #if defined(__linux__) syscall(SYS_tkill, m_thread_id, BreakFromRunCodeSignal); -#elif defined(__APPLE__) && defined(__aarch64__) +#elif defined(__APPLE__) asm volatile( "mov x0, %0\n" // m_thread_id "mov x1, %1\n" // BreakFromRunCodeSignal @@ -387,19 +470,13 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) { } } -[[maybe_unused]] const std::size_t CACHE_PAGE_SIZE = Common::HostPageSize; - -void ArmNce::ClearInstructionCache() { -#ifdef __aarch64__ +void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) { // Ensure all previous memory operations complete asm volatile("dsb ish\n" "dsb ish\n" "isb" ::: "memory"); -#endif -} - -void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) { - this->ClearInstructionCache(); } } // namespace Core + +#endif // #ifdef __aarch64__ \ No newline at end of file diff --git a/src/core/arm/nce/arm_nce.h b/src/core/arm/nce/arm_nce.h index be9b304c4c..a28288801f 100644 --- a/src/core/arm/nce/arm_nce.h +++ b/src/core/arm/nce/arm_nce.h @@ -16,6 +16,15 @@ namespace Core { class System; +#ifdef __APPLE__ +// TLS index for NativeExecutionParameters in pthreads. +// This value is actually reserved for old versions of iOSSimulator, however we aren't iOSSimulator, +// so we can manually initialize and use it. +// https://github.com/apple-oss-distributions/libpthread/blob/42d026df5b07825070f60134b980a1ec2552dfee/private/pthread/tsd_private.h#L241-L245 +constexpr pthread_key_t CONTEXT_KEY = 210; +#endif + + class ArmNce final : public ArmInterface { public: ArmNce(System& system, bool uses_wall_clock, std::size_t core_index); @@ -39,7 +48,6 @@ public: u32 GetSvcNumber() const override; void SignalInterrupt(Kernel::KThread* thread) override; - void ClearInstructionCache() override; void InvalidateCacheRange(u64 addr, std::size_t size) override; void LockThread(Kernel::KThread* thread) override; @@ -53,7 +61,8 @@ protected: void RewindBreakpointInstruction() override {} private: - // Assembly definitions. + // Only confirmed to be valid on Apple systems. + static void* GetGuestParameters(); static HaltReason ReturnToRunCodeByTrampoline(void* tpidr, GuestContext* ctx, u64 trampoline_addr); static HaltReason ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr); @@ -62,20 +71,16 @@ private: void* raw_context); static void BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context); static void GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context); - static void GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context); + static void GuestMemoryFaultSignalHandler(int sig, void* info, void* raw_context); static void LockThreadParameters(void* tpidr); static void UnlockThreadParameters(void* tpidr); -private: // C++ implementation functions for assembly definitions. static void* RestoreGuestContext(void* raw_context); static void SaveGuestContext(GuestContext* ctx, void* raw_context); static bool HandleFailedGuestFault(GuestContext* ctx, void* info, void* raw_context); static bool HandleGuestAlignmentFault(GuestContext* ctx, void* info, void* raw_context); - static bool HandleGuestAccessFault(GuestContext* ctx, void* info, void* raw_context); - static void HandleHostAlignmentFault(int sig, void* info, void* raw_context); - static void HandleHostAccessFault(int sig, void* info, void* raw_context); public: Core::System& m_system; diff --git a/src/core/arm/nce/arm_nce.s b/src/core/arm/nce/arm_nce.s index bb21fbdb17..b14438a50c 100644 --- a/src/core/arm/nce/arm_nce.s +++ b/src/core/arm/nce/arm_nce.s @@ -150,94 +150,6 @@ ASM_FUNCTION_START _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_ /* Incorrect TLS magic, so this is a spurious signal. */ ret - -/* static void Core::ArmNce::GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context) */ -ASM_FUNCTION_START _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_ - /* Check to see if we have the correct TLS magic. */ - mrs x8, tpidr_el0 - ldr w9, [x8, #(TpidrEl0TlsMagic)] - - LOAD_IMMEDIATE_32(w10, TlsMagic) - - cmp w9, w10 - b.eq 1f - - /* Incorrect TLS magic, so this is a host fault. */ - /* Tail call the handler. */ - b SYM(_ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_) - -1: - /* Correct TLS magic, so this is a guest fault. */ - stp x29, x30, [sp, #-0x20]! - str x19, [sp, #0x10] - mov x29, sp - - /* Save the old tpidr_el0. */ - mov x19, x8 - - /* Restore host tpidr_el0. */ - ldr x0, [x8, #(TpidrEl0NativeContext)] - ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)] - msr tpidr_el0, x3 - - /* Call the handler. */ - bl SYM(_ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_) - - /* If the handler returned false, we want to preserve the host tpidr_el0. */ - cbz x0, 2f - - /* Otherwise, restore guest tpidr_el0. */ - msr tpidr_el0, x19 - -2: - ldr x19, [sp, #0x10] - ldp x29, x30, [sp], #0x20 - ret - -/* static void Core::ArmNce::GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context) */ -ASM_FUNCTION_START _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_ - /* Check to see if we have the correct TLS magic. */ - mrs x8, tpidr_el0 - ldr w9, [x8, #(TpidrEl0TlsMagic)] - - LOAD_IMMEDIATE_32(w10, TlsMagic) - - cmp w9, w10 - b.eq 1f - - /* Incorrect TLS magic, so this is a host fault. */ - /* Tail call the handler. */ - b SYM(_ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_) - -1: - /* Correct TLS magic, so this is a guest fault. */ - stp x29, x30, [sp, #-0x20]! - str x19, [sp, #0x10] - mov x29, sp - - /* Save the old tpidr_el0. */ - mov x19, x8 - - /* Restore host tpidr_el0. */ - ldr x0, [x8, #(TpidrEl0NativeContext)] - ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)] - msr tpidr_el0, x3 - - /* Call the handler. */ - bl SYM(_ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_) - - /* If the handler returned false, we want to preserve the host tpidr_el0. */ - cbz x0, 2f - - /* Otherwise, restore guest tpidr_el0. */ - msr tpidr_el0, x19 - -2: - ldr x19, [sp, #0x10] - ldp x29, x30, [sp], #0x20 - ret - - /* static void Core::ArmNce::LockThreadParameters(void* tpidr) */ ASM_FUNCTION_START _ZN4Core6ArmNce20LockThreadParametersEPv /* Offset to lock member. */ diff --git a/src/core/arm/nce/guest_context.h b/src/core/arm/nce/guest_context.h index b2020ad7d6..fe085665ac 100644 --- a/src/core/arm/nce/guest_context.h +++ b/src/core/arm/nce/guest_context.h @@ -131,15 +131,6 @@ private: #endif }; -// Verify assembly offsets. -static_assert(offsetof(GuestContext, sp) == GuestContextSp); -static_assert(offsetof(GuestContext, host_ctx) == GuestContextHostContext); -static_assert(offsetof(HostContext, host_sp) == HostContextSpTpidrEl0); -static_assert(offsetof(HostContext, host_tpidr_el0) - 8 == HostContextSpTpidrEl0); -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 __APPLE__ // 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); diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index d793aea940..ca9291653c 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp @@ -365,12 +365,26 @@ size_t Patcher::GetPreSectionSize() const noexcept { return Common::AlignUp(m_patch_instructions_pre.size() * sizeof(u32), Common::HostPageSize); } +__attribute__((always_inline)) +void Patcher::LoadTLS(oaknut::VectorCodeGenerator& cg, oaknut::XReg out) { +#ifdef __APPLE__ + // The kernel zeros out TPIDR_EL0 too unpredictably, so we use pthreads TLS instead + // (which we can optimize by JIT'ing the key offset) + + // https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/libsyscall/os/tsd.h#L156-L189 + cg.MRS(out, oaknut::SystemReg::TPIDRRO_EL0); + cg.LDR(out, out, CONTEXT_KEY * 8); +#else + cg.MRS(out, oaknut::SystemReg::TPIDR_EL0); +#endif +} + void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) { // This function was called, which modifies X30, so use that as a scratch register. // SP contains the guest X30, so save our return X30 to SP + 8, since we have allocated 16 bytes // of stack. cg.STR(X30, SP, 8); - cg.MRS(X30, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X30); cg.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context)); // Load system registers. @@ -403,7 +417,7 @@ void Patcher::WriteSaveContext(oaknut::VectorCodeGenerator& cg) { // SP contains the guest X30, so save our X30 to SP + 8, since we have allocated 16 bytes of // stack. cg.STR(X30, SP, 8); - cg.MRS(X30, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X30); cg.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context)); // Store all general-purpose registers except X30. @@ -452,7 +466,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut // Now that we've saved all registers, we can use any registers as scratch. // Store PC + 4 to arm interface, since we know the instruction offset from the entry point. oaknut::Label pc_after_svc; - cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X1); cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context)); cg.LDR(X2, pc_after_svc); cg.STR(X2, X1, offsetof(GuestContext, pc)); @@ -482,7 +496,9 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut static_assert(offsetof(HostContext, host_sp) + 8 == offsetof(HostContext, host_tpidr_el0)); cg.LDP(X2, X3, X1, offsetof(HostContext, host_sp)); cg.MOV(SP, X2); +#ifndef __APPLE__ cg.MSR(oaknut::SystemReg::TPIDR_EL0, X3); +#endif // Load callee-saved host registers and return to host. static constexpr size_t HOST_REGS_OFF = offsetof(HostContext, host_saved_regs); @@ -509,7 +525,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut // Host called this location. Save the return address so we can // unwind the stack properly when jumping back. - cg.MRS(X2, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X2); cg.LDR(X2, X2, offsetof(NativeExecutionParameters, native_context)); cg.ADD(X0, X2, offsetof(GuestContext, host_ctx)); cg.STR(X30, X0, offsetof(HostContext, host_saved_regs) + 11 * sizeof(u64)); @@ -522,7 +538,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut // Use X1 as a scratch register to restore X30. cg.STR(X1, SP, PRE_INDEXED, -16); - cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X1); cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context)); cg.LDR(X30, X1, offsetof(GuestContext, cpu_registers) + sizeof(u64) * 30); cg.LDR(X1, SP, POST_INDEXED, 16); @@ -544,10 +560,10 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut this->WriteModulePc(module_dest); } +// Retrieve emulated TLS register from GuestContext. void Patcher::WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, oaknut::SystemReg src_reg, oaknut::VectorCodeGenerator& cg) { - // Retrieve emulated TLS register from GuestContext. - cg.MRS(dest_reg, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, dest_reg); if (src_reg == oaknut::SystemReg::TPIDRRO_EL0) { cg.LDR(dest_reg, dest_reg, offsetof(NativeExecutionParameters, tpidrro_el0)); } else { @@ -566,7 +582,7 @@ void Patcher::WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg, cg.STR(scratch_reg, SP, PRE_INDEXED, -16); // Save guest value to NativeExecutionParameters::tpidr_el0. - cg.MRS(scratch_reg, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, scratch_reg); cg.STR(src_reg, scratch_reg, offsetof(NativeExecutionParameters, tpidr_el0)); // Restore scratch register. @@ -636,7 +652,7 @@ void Patcher::LockContext(oaknut::VectorCodeGenerator& cg) { // Reload lock pointer. cg.l(retry); cg.CLREX(); - cg.MRS(X0, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X0); cg.ADD(X0, X0, offsetof(NativeExecutionParameters, lock)); static_assert(SpinLockLocked == 0); @@ -662,7 +678,7 @@ void Patcher::UnlockContext(oaknut::VectorCodeGenerator& cg) { cg.STP(X0, X1, SP, PRE_INDEXED, -16); // Load lock pointer. - cg.MRS(X0, oaknut::SystemReg::TPIDR_EL0); + LoadTLS(cg, X0); cg.ADD(X0, X0, offsetof(NativeExecutionParameters, lock)); // Load SpinLockUnlocked. diff --git a/src/core/arm/nce/patcher.h b/src/core/arm/nce/patcher.h index 980a0c81e0..01c32219cf 100644 --- a/src/core/arm/nce/patcher.h +++ b/src/core/arm/nce/patcher.h @@ -73,6 +73,7 @@ private: }; // Core implementations with explicit code generator + void LoadTLS(oaknut::VectorCodeGenerator& cg, oaknut::XReg out); void WriteLoadContext(oaknut::VectorCodeGenerator& code); void WriteSaveContext(oaknut::VectorCodeGenerator& code); void LockContext(oaknut::VectorCodeGenerator& code); diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index 1fba3db84a..d569ccd0e8 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -283,6 +283,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, // TODO: linear search support for Aligned? allocated_block = cur_manager->AllocateBlock(index, random); } + + ASSERT(Common::IsAligned(GetInteger(allocated_block), Common::HostPageSize)); if (allocated_block == 0) { break; } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 95ba1b4d76..76c8bd7380 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -668,12 +668,17 @@ public: public: // TODO: This shouldn't be defined in kernel namespace struct NativeExecutionParameters { +#if defined(__APPLE__) && HAS_NCE + // Are we in actual guest code? + bool is_actually_running{}; +#endif + // Are we in any stage of performing guest operations? + bool is_running{}; + u32 magic{Common::MakeMagic('Y', 'U', 'Z', 'U')}; + std::atomic lock{1}; u64 tpidr_el0{}; u64 tpidrro_el0{}; void* native_context{}; - std::atomic lock{1}; - bool is_running{}; - u32 magic{Common::MakeMagic('Y', 'U', 'Z', 'U')}; }; NativeExecutionParameters& GetNativeExecutionParameters() {