mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
macOS (Apple Silicon) support: native build running under Rosetta 2 with MoltenVK (#102)
* macos: POSIX platform layer (host fault handler, virtual memory) - hostException: Mach/POSIX signal-based host fault handler mirroring the Windows vectored handler (SIGSEGV/SIGBUS/SIGILL), behind '#elif defined(__APPLE__)'. Windows and Linux branches are untouched. - sysLinuxVirtual: mach_vm_region-based is_mapped (no /proc/self/maps on macOS), PTHREAD_MUTEX_NORMAL, and a MAP_FIXED carve-in-place allocator that never leaves an unmapped hole for dyld/Rosetta/Metal to claim. All __APPLE__-guarded; the original Linux allocator path is preserved verbatim. - sysLinuxDbg/sysLinuxFileIO: libgen.h for basename(), and a POSIX opendir/readdir implementation of SysFileGetDents (previously a stub). * macos: guest kernel backing, threads, and POSIX libs - memory/memoryAddressSpace: anonymous shm_open backing (macOS has no memfd_create) and re-reserve-on-unmap so a guest MAP_FIXED remap never destroys a host mapping (__APPLE__-guarded). Drops host <sys/mman.h> MAP_* macros so the guest's constexpr MAP_* constants compile (no-op on Windows). - pthread: undef the host PTHREAD_STACK_MIN macro; on non-Windows, pin the stack-switch asm's guest rsp/rbp to callee-saved r14/r15 (the template clobbers r12/r13); __APPLE__ no-op for the absent pthread_condattr_setclock. The Windows stack-switch asm is byte-identical. - network: define SOCKET/INVALID_SOCKET for the non-Windows paths (were undefined at 20+ use sites), and rename the non-Windows kernel_clock_* helpers to the CamelCase names the callers already use. Both repair the shared non-Windows build. Integer reinterpret_cast -> static_cast. * loader: pin stack-switch asm operands to callee-saved registers RunEntry switches to the guest stack with an asm template that clobbers r12/r13 before consuming its inputs. With plain "r" constraints the compiler may place func/guest_rsp/guest_rbp into r12/r13, so 'callq *func' jumps through the saved host rsp -- a latent miscompile on every platform that any unrelated codegen change can trigger. Pin the inputs to rbx/r14/r15, which the template never touches and the SysV callee preserves. General correctness fix (not macOS-specific); the same fix is applied to pthread RunOnGuestStack. * macos: Vulkan/MoltenVK graphics enablement - pageManager: GPU write-tracking via Mach VM queries + mprotect (mprotect cannot report the previous protection, so the expected-old check is dropped), thread id via pthread_mach_thread_np, 4 KB page-size check -- __APPLE__-guarded. - shaders/renderDraw/vulkanWindow: MoltenVK lacks VK_EXT_color_write_enable, VK_EXT_depth_clip_enable and depthBounds; fall back to static color-write masks and default depth clipping, request VK_KHR_portability_subset, and reuse the graphics queue for present when only one queue is exposed. Non-Apple pipeline/extension setup is unchanged. - window: optional borderless window (KYTY_BORDERLESS) to sidestep a Rosetta NSException in macOS window chrome. * graphics: macOS thread identity for region tracking Region-ownership locks resolve the current thread via GetCurrentThreadId() on Windows and EXIT elsewhere. Use the Mach thread port on macOS (nonzero per-thread id; 0 stays the no-owner sentinel). * macos: marshal AppKit window operations to the main thread The present worker thread shows the window, updates its icon and title, and recreates a lost Vulkan surface. AppKit traps with 'Must only be used from the main thread' when these run off the main thread. Route them through a small task queue drained by the SDL main loop (an SDL_USEREVENT wakes the loop when it is blocked in SDL_WaitEvent). Title updates are fire-and-forget; showing the window and surface recreation wait for completion. Windows and Linux call the SDL functions directly, as before. * build: ignore the _Build output directory _Build is the conventional out-of-tree build location (only _Build/vscode-clang was ignored); a stray git add could sweep build artifacts into a commit. * macos: isolate stack-switch workaround --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -191,9 +191,15 @@ public:
|
||||
SetFailure(failure_reason, FailureReason::ReserveAlignedFailed);
|
||||
return 0;
|
||||
}
|
||||
#if !defined(__APPLE__)
|
||||
// On macOS the PROT_NONE reservation is left in place: MapView's MAP_FIXED
|
||||
// replaces it atomically, so the range never becomes a hole that dyld,
|
||||
// Rosetta, or Metal background threads could claim (which the subsequent
|
||||
// MAP_FIXED would then silently destroy).
|
||||
if (!ReleaseReservedProbe(reserved, failure_reason)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (MapFixed(reserved, size, backing_offset, mode, failure_reason)) {
|
||||
return reserved;
|
||||
}
|
||||
@@ -1061,7 +1067,17 @@ private:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static bool UnmapView(void* vaddr, uint64_t size) { return munmap(vaddr, size) == 0; }
|
||||
static bool UnmapView(void* vaddr, uint64_t size) {
|
||||
#if defined(__APPLE__)
|
||||
// Re-reserve instead of freeing: the guest may MAP_FIXED-remap this range
|
||||
// later, and that must never destroy a host mapping (dyld, Rosetta, Metal)
|
||||
// that moved into the hole in the meantime.
|
||||
return mmap(vaddr, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
||||
-1, 0) != MAP_FAILED;
|
||||
#else
|
||||
return munmap(vaddr, size) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool UnmapViewPreservePlaceholder(void* /*vaddr*/, uint64_t /*size*/) { return false; }
|
||||
|
||||
|
||||
+30
-4
@@ -58,6 +58,12 @@ namespace LibKernel {
|
||||
|
||||
LIB_NAME("libkernel", "libkernel");
|
||||
|
||||
// macOS's <pthread.h>/<limits.h> define PTHREAD_STACK_MIN as a macro; the emulator
|
||||
// wants its own guest-side value with the same name, so drop the host macro here.
|
||||
#ifdef PTHREAD_STACK_MIN
|
||||
#undef PTHREAD_STACK_MIN
|
||||
#endif
|
||||
|
||||
constexpr int KEYS_MAX = 256;
|
||||
constexpr int DESTRUCTOR_ITERATIONS = 4;
|
||||
constexpr size_t PTHREAD_STACK_DEFAULT = 0x100000;
|
||||
@@ -795,9 +801,9 @@ static KYTY_SYSV_ABI void* RunOnGuestStack(void* arg, pthread_entry_func_t func,
|
||||
}
|
||||
|
||||
// The guest ABI expects the entry argument in rdi and a 16-byte aligned stack before call.
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
asm volatile("pushq %%r12\n\t"
|
||||
"pushq %%r13\n\t"
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
"pushq %%r14\n\t"
|
||||
"pushq %%r15\n\t"
|
||||
"movq %%gs:0x08, %%r14\n\t"
|
||||
@@ -805,7 +811,6 @@ static KYTY_SYSV_ABI void* RunOnGuestStack(void* arg, pthread_entry_func_t func,
|
||||
"xorq %%rcx, %%rcx\n\t"
|
||||
"movq %%rcx, %%gs:0x08\n\t"
|
||||
"movq %%rcx, %%gs:0x10\n\t"
|
||||
#endif
|
||||
"movq %%rsp, %%r12\n\t"
|
||||
"movq %%rbp, %%r13\n\t"
|
||||
"movq %[guest_rsp], %%rsp\n\t"
|
||||
@@ -813,12 +818,10 @@ static KYTY_SYSV_ABI void* RunOnGuestStack(void* arg, pthread_entry_func_t func,
|
||||
"callq *%%rsi\n\t"
|
||||
"movq %%r13, %%rbp\n\t"
|
||||
"movq %%r12, %%rsp\n\t"
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
"movq %%r14, %%gs:0x08\n\t"
|
||||
"movq %%r15, %%gs:0x10\n\t"
|
||||
"popq %%r15\n\t"
|
||||
"popq %%r14\n\t"
|
||||
#endif
|
||||
"popq %%r13\n\t"
|
||||
"popq %%r12\n\t"
|
||||
: "=a"(ret), "+D"(arg), "+S"(func)
|
||||
@@ -826,6 +829,29 @@ static KYTY_SYSV_ABI void* RunOnGuestStack(void* arg, pthread_entry_func_t func,
|
||||
: "cc", "memory", "rcx", "rdx", "r8", "r9", "r10", "r11", "xmm0", "xmm1", "xmm2",
|
||||
"xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
|
||||
"xmm12", "xmm13", "xmm14", "xmm15");
|
||||
#else
|
||||
// Pin the stack operands to registers the template never touches (r14/r15 are
|
||||
// SysV callee-saved, so guest code preserves them): plain "r" constraints may
|
||||
// allocate them into r12/r13, which the template overwrites before use.
|
||||
register uintptr_t guest_rsp_reg asm("r14") = guest_rsp;
|
||||
register uintptr_t guest_rbp_reg asm("r15") = guest_rbp;
|
||||
asm volatile("pushq %%r12\n\t"
|
||||
"pushq %%r13\n\t"
|
||||
"movq %%rsp, %%r12\n\t"
|
||||
"movq %%rbp, %%r13\n\t"
|
||||
"movq %[guest_rsp], %%rsp\n\t"
|
||||
"movq %[guest_rbp], %%rbp\n\t"
|
||||
"callq *%%rsi\n\t"
|
||||
"movq %%r13, %%rbp\n\t"
|
||||
"movq %%r12, %%rsp\n\t"
|
||||
"popq %%r13\n\t"
|
||||
"popq %%r12\n\t"
|
||||
: "=a"(ret), "+D"(arg), "+S"(func)
|
||||
: [guest_rsp] "r"(guest_rsp_reg), [guest_rbp] "r"(guest_rbp_reg)
|
||||
: "cc", "memory", "rcx", "rdx", "r8", "r9", "r10", "r11", "xmm0", "xmm1", "xmm2",
|
||||
"xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
|
||||
"xmm12", "xmm13", "xmm14", "xmm15");
|
||||
#endif
|
||||
|
||||
g_guest_entry_return_rsp = 0;
|
||||
if (g_pthread_self != nullptr) {
|
||||
|
||||
Reference in New Issue
Block a user