Browse Source

[nce] macOS TLS, start inlining asm code

remotes/1785372757367212240/tmp_refs/heads/variable-page-size
Exverge 1 month ago
parent
commit
81a81c10de
No known key found for this signature in database GPG Key ID: DAD399BCC5FB77E4
  1. 185
      src/core/arm/nce/arm_nce.cpp
  2. 19
      src/core/arm/nce/arm_nce.h
  3. 88
      src/core/arm/nce/arm_nce.s
  4. 9
      src/core/arm/nce/guest_context.h
  5. 36
      src/core/arm/nce/patcher.cpp
  6. 1
      src/core/arm/nce/patcher.h
  7. 2
      src/core/hle/kernel/k_memory_manager.cpp
  8. 11
      src/core/hle/kernel/k_thread.h

185
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 <cinttypes>
#include <memory>
@ -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<NativeExecutionParameters*>(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<siginfo_t*>(raw_info);
auto* guest_ctx = static_cast<GuestContext*>(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<u64>(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<ucontext_t*>(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<siginfo_t*>(raw_info), raw_context);
} else if (sig == SIGBUS) {
g_orig_bus_action.sa_sigaction(sig, static_cast<siginfo_t*>(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<ucontext_t*>(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<ucontext_t*>(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<siginfo_t*>(raw_info);
// Try to handle an invalid access.
// TODO: handle accesses which split a page?
const Common::ProcessAddress addr =
(reinterpret_cast<u64>(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<siginfo_t*>(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<siginfo_t*>(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<HandlerType>(&ArmNce::GuestAccessFaultSignalHandler);
reinterpret_cast<HandlerType>(&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__

19
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;

88
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. */

9
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);

36
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.

1
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);

2
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;
}

11
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<u32> lock{1};
u64 tpidr_el0{};
u64 tpidrro_el0{};
void* native_context{};
std::atomic<u32> lock{1};
bool is_running{};
u32 magic{Common::MakeMagic('Y', 'U', 'Z', 'U')};
};
NativeExecutionParameters& GetNativeExecutionParameters() {

Loading…
Cancel
Save