cosmopolitan/libc/calls/xnutrampoline.c

476 lines
15 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
#include "libc/str/str.h"
/**
* @fileoverview XNU kernel callback normalization.
*/
union __darwin_sigval {
int32_t sival_int;
void *sival_ptr;
};
struct __darwin_siginfo {
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
uint32_t si_uid;
int32_t si_status;
void *si_addr;
union __darwin_sigval si_value;
int64_t si_band;
uint64_t __pad[7];
};
struct __darwin_sigaltstack {
void *ss_sp;
uint64_t ss_size;
int32_t ss_flags;
};
struct __darwin_fp_control {
uint16_t __invalid : 1, __denorm : 1, __zdiv : 1, __ovrfl : 1, __undfl : 1,
__precis : 1, : 2, __pc : 2, __rc : 2, : 1, : 3;
};
struct __darwin_fp_status {
uint16_t __invalid : 1, __denorm : 1, __zdiv : 1, __ovrfl : 1, __undfl : 1,
__precis : 1, __stkflt : 1, __errsumm : 1, __c0 : 1, __c1 : 1, __c2 : 1,
__tos : 3, __c3 : 1, __busy : 1;
};
struct __darwin_mmst_reg {
char __mmst_reg[10];
char __mmst_rsrv[6];
};
struct __darwin_xmm_reg {
char __xmm_reg[16];
};
struct __darwin_ymm_reg {
char __ymm_reg[32];
};
struct __darwin_zmm_reg {
char __zmm_reg[64];
};
struct __darwin_opmask_reg {
char __opmask_reg[8];
};
struct __darwin_x86_thread_state64 {
uint64_t __rax;
uint64_t __rbx;
uint64_t __rcx;
uint64_t __rdx;
uint64_t __rdi;
uint64_t __rsi;
uint64_t __rbp;
uint64_t __rsp;
uint64_t __r8;
uint64_t __r9;
uint64_t __r10;
uint64_t __r11;
uint64_t __r12;
uint64_t __r13;
uint64_t __r14;
uint64_t __r15;
uint64_t __rip;
uint64_t __rflags;
uint64_t __cs;
uint64_t __fs;
uint64_t __gs;
};
struct __darwin_x86_thread_full_state64 {
struct __darwin_x86_thread_state64 ss64;
uint64_t __ds;
uint64_t __es;
uint64_t __ss;
uint64_t __gsbase;
};
struct __darwin_x86_float_state64 {
int32_t __fpu_reserved[2];
struct __darwin_fp_control __fpu_fcw;
struct __darwin_fp_status __fpu_fsw;
uint8_t __fpu_ftw;
uint8_t __fpu_rsrv1;
uint16_t __fpu_fop;
uint32_t __fpu_ip;
uint16_t __fpu_cs;
uint16_t __fpu_rsrv2;
uint32_t __fpu_dp;
uint16_t __fpu_ds;
uint16_t __fpu_rsrv3;
uint32_t __fpu_mxcsr;
uint32_t __fpu_mxcsrmask;
struct __darwin_mmst_reg __fpu_stmm0;
struct __darwin_mmst_reg __fpu_stmm1;
struct __darwin_mmst_reg __fpu_stmm2;
struct __darwin_mmst_reg __fpu_stmm3;
struct __darwin_mmst_reg __fpu_stmm4;
struct __darwin_mmst_reg __fpu_stmm5;
struct __darwin_mmst_reg __fpu_stmm6;
struct __darwin_mmst_reg __fpu_stmm7;
struct __darwin_xmm_reg __fpu_xmm0;
struct __darwin_xmm_reg __fpu_xmm1;
struct __darwin_xmm_reg __fpu_xmm2;
struct __darwin_xmm_reg __fpu_xmm3;
struct __darwin_xmm_reg __fpu_xmm4;
struct __darwin_xmm_reg __fpu_xmm5;
struct __darwin_xmm_reg __fpu_xmm6;
struct __darwin_xmm_reg __fpu_xmm7;
struct __darwin_xmm_reg __fpu_xmm8;
struct __darwin_xmm_reg __fpu_xmm9;
struct __darwin_xmm_reg __fpu_xmm10;
struct __darwin_xmm_reg __fpu_xmm11;
struct __darwin_xmm_reg __fpu_xmm12;
struct __darwin_xmm_reg __fpu_xmm13;
struct __darwin_xmm_reg __fpu_xmm14;
struct __darwin_xmm_reg __fpu_xmm15;
char __fpu_rsrv4[6 * 16];
int32_t __fpu_reserved1;
};
struct __darwin_x86_avx_state64 {
int32_t __fpu_reserved[2];
struct __darwin_fp_control __fpu_fcw;
struct __darwin_fp_status __fpu_fsw;
uint8_t __fpu_ftw;
uint8_t __fpu_rsrv1;
uint16_t __fpu_fop;
uint32_t __fpu_ip;
uint16_t __fpu_cs;
uint16_t __fpu_rsrv2;
uint32_t __fpu_dp;
uint16_t __fpu_ds;
uint16_t __fpu_rsrv3;
uint32_t __fpu_mxcsr;
uint32_t __fpu_mxcsrmask;
struct __darwin_mmst_reg __fpu_stmm0;
struct __darwin_mmst_reg __fpu_stmm1;
struct __darwin_mmst_reg __fpu_stmm2;
struct __darwin_mmst_reg __fpu_stmm3;
struct __darwin_mmst_reg __fpu_stmm4;
struct __darwin_mmst_reg __fpu_stmm5;
struct __darwin_mmst_reg __fpu_stmm6;
struct __darwin_mmst_reg __fpu_stmm7;
struct __darwin_xmm_reg __fpu_xmm0;
struct __darwin_xmm_reg __fpu_xmm1;
struct __darwin_xmm_reg __fpu_xmm2;
struct __darwin_xmm_reg __fpu_xmm3;
struct __darwin_xmm_reg __fpu_xmm4;
struct __darwin_xmm_reg __fpu_xmm5;
struct __darwin_xmm_reg __fpu_xmm6;
struct __darwin_xmm_reg __fpu_xmm7;
struct __darwin_xmm_reg __fpu_xmm8;
struct __darwin_xmm_reg __fpu_xmm9;
struct __darwin_xmm_reg __fpu_xmm10;
struct __darwin_xmm_reg __fpu_xmm11;
struct __darwin_xmm_reg __fpu_xmm12;
struct __darwin_xmm_reg __fpu_xmm13;
struct __darwin_xmm_reg __fpu_xmm14;
struct __darwin_xmm_reg __fpu_xmm15;
char __fpu_rsrv4[6 * 16];
int32_t __fpu_reserved1;
char __avx_reserved1[64];
struct __darwin_xmm_reg __fpu_ymmh0;
struct __darwin_xmm_reg __fpu_ymmh1;
struct __darwin_xmm_reg __fpu_ymmh2;
struct __darwin_xmm_reg __fpu_ymmh3;
struct __darwin_xmm_reg __fpu_ymmh4;
struct __darwin_xmm_reg __fpu_ymmh5;
struct __darwin_xmm_reg __fpu_ymmh6;
struct __darwin_xmm_reg __fpu_ymmh7;
struct __darwin_xmm_reg __fpu_ymmh8;
struct __darwin_xmm_reg __fpu_ymmh9;
struct __darwin_xmm_reg __fpu_ymmh10;
struct __darwin_xmm_reg __fpu_ymmh11;
struct __darwin_xmm_reg __fpu_ymmh12;
struct __darwin_xmm_reg __fpu_ymmh13;
struct __darwin_xmm_reg __fpu_ymmh14;
struct __darwin_xmm_reg __fpu_ymmh15;
};
struct __darwin_x86_avx512_state64 {
int32_t __fpu_reserved[2];
struct __darwin_fp_control __fpu_fcw;
struct __darwin_fp_status __fpu_fsw;
uint8_t __fpu_ftw;
uint8_t __fpu_rsrv1;
uint16_t __fpu_fop;
uint32_t __fpu_ip;
uint16_t __fpu_cs;
uint16_t __fpu_rsrv2;
uint32_t __fpu_dp;
uint16_t __fpu_ds;
uint16_t __fpu_rsrv3;
uint32_t __fpu_mxcsr;
uint32_t __fpu_mxcsrmask;
struct __darwin_mmst_reg __fpu_stmm0;
struct __darwin_mmst_reg __fpu_stmm1;
struct __darwin_mmst_reg __fpu_stmm2;
struct __darwin_mmst_reg __fpu_stmm3;
struct __darwin_mmst_reg __fpu_stmm4;
struct __darwin_mmst_reg __fpu_stmm5;
struct __darwin_mmst_reg __fpu_stmm6;
struct __darwin_mmst_reg __fpu_stmm7;
struct __darwin_xmm_reg __fpu_xmm0;
struct __darwin_xmm_reg __fpu_xmm1;
struct __darwin_xmm_reg __fpu_xmm2;
struct __darwin_xmm_reg __fpu_xmm3;
struct __darwin_xmm_reg __fpu_xmm4;
struct __darwin_xmm_reg __fpu_xmm5;
struct __darwin_xmm_reg __fpu_xmm6;
struct __darwin_xmm_reg __fpu_xmm7;
struct __darwin_xmm_reg __fpu_xmm8;
struct __darwin_xmm_reg __fpu_xmm9;
struct __darwin_xmm_reg __fpu_xmm10;
struct __darwin_xmm_reg __fpu_xmm11;
struct __darwin_xmm_reg __fpu_xmm12;
struct __darwin_xmm_reg __fpu_xmm13;
struct __darwin_xmm_reg __fpu_xmm14;
struct __darwin_xmm_reg __fpu_xmm15;
char __fpu_rsrv4[6 * 16];
int32_t __fpu_reserved1;
char __avx_reserved1[64];
struct __darwin_xmm_reg __fpu_ymmh0;
struct __darwin_xmm_reg __fpu_ymmh1;
struct __darwin_xmm_reg __fpu_ymmh2;
struct __darwin_xmm_reg __fpu_ymmh3;
struct __darwin_xmm_reg __fpu_ymmh4;
struct __darwin_xmm_reg __fpu_ymmh5;
struct __darwin_xmm_reg __fpu_ymmh6;
struct __darwin_xmm_reg __fpu_ymmh7;
struct __darwin_xmm_reg __fpu_ymmh8;
struct __darwin_xmm_reg __fpu_ymmh9;
struct __darwin_xmm_reg __fpu_ymmh10;
struct __darwin_xmm_reg __fpu_ymmh11;
struct __darwin_xmm_reg __fpu_ymmh12;
struct __darwin_xmm_reg __fpu_ymmh13;
struct __darwin_xmm_reg __fpu_ymmh14;
struct __darwin_xmm_reg __fpu_ymmh15;
struct __darwin_opmask_reg __fpu_k0;
struct __darwin_opmask_reg __fpu_k1;
struct __darwin_opmask_reg __fpu_k2;
struct __darwin_opmask_reg __fpu_k3;
struct __darwin_opmask_reg __fpu_k4;
struct __darwin_opmask_reg __fpu_k5;
struct __darwin_opmask_reg __fpu_k6;
struct __darwin_opmask_reg __fpu_k7;
struct __darwin_ymm_reg __fpu_zmmh0;
struct __darwin_ymm_reg __fpu_zmmh1;
struct __darwin_ymm_reg __fpu_zmmh2;
struct __darwin_ymm_reg __fpu_zmmh3;
struct __darwin_ymm_reg __fpu_zmmh4;
struct __darwin_ymm_reg __fpu_zmmh5;
struct __darwin_ymm_reg __fpu_zmmh6;
struct __darwin_ymm_reg __fpu_zmmh7;
struct __darwin_ymm_reg __fpu_zmmh8;
struct __darwin_ymm_reg __fpu_zmmh9;
struct __darwin_ymm_reg __fpu_zmmh10;
struct __darwin_ymm_reg __fpu_zmmh11;
struct __darwin_ymm_reg __fpu_zmmh12;
struct __darwin_ymm_reg __fpu_zmmh13;
struct __darwin_ymm_reg __fpu_zmmh14;
struct __darwin_ymm_reg __fpu_zmmh15;
struct __darwin_zmm_reg __fpu_zmm16;
struct __darwin_zmm_reg __fpu_zmm17;
struct __darwin_zmm_reg __fpu_zmm18;
struct __darwin_zmm_reg __fpu_zmm19;
struct __darwin_zmm_reg __fpu_zmm20;
struct __darwin_zmm_reg __fpu_zmm21;
struct __darwin_zmm_reg __fpu_zmm22;
struct __darwin_zmm_reg __fpu_zmm23;
struct __darwin_zmm_reg __fpu_zmm24;
struct __darwin_zmm_reg __fpu_zmm25;
struct __darwin_zmm_reg __fpu_zmm26;
struct __darwin_zmm_reg __fpu_zmm27;
struct __darwin_zmm_reg __fpu_zmm28;
struct __darwin_zmm_reg __fpu_zmm29;
struct __darwin_zmm_reg __fpu_zmm30;
struct __darwin_zmm_reg __fpu_zmm31;
};
struct __darwin_x86_exception_state64 {
uint16_t __trapno;
uint16_t __cpu;
uint32_t __err;
uint64_t __faultvaddr;
};
struct __darwin_x86_debug_state64 {
uint64_t __dr0;
uint64_t __dr1;
uint64_t __dr2;
uint64_t __dr3;
uint64_t __dr4;
uint64_t __dr5;
uint64_t __dr6;
uint64_t __dr7;
};
struct __darwin_x86_cpmu_state64 {
uint64_t __ctrs[16];
};
struct __darwin_mcontext64_full {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_full_state64 __ss;
struct __darwin_x86_float_state64 __fs;
};
struct __darwin_mcontext_avx64 {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_state64 __ss;
struct __darwin_x86_avx_state64 __fs;
};
struct __darwin_mcontext_avx64_full {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_full_state64 __ss;
struct __darwin_x86_avx_state64 __fs;
};
struct __darwin_mcontext_avx512_64 {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_state64 __ss;
struct __darwin_x86_avx512_state64 __fs;
};
struct __darwin_mcontext_avx512_64_full {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_full_state64 __ss;
struct __darwin_x86_avx512_state64 __fs;
};
struct __darwin_mcontext64 {
struct __darwin_x86_exception_state64 __es;
struct __darwin_x86_thread_state64 __ss;
struct __darwin_x86_float_state64 __fs;
};
struct __darwin_ucontext {
int32_t uc_onstack;
uint32_t uc_sigmask;
struct __darwin_sigaltstack uc_stack;
struct __darwin_ucontext *uc_link;
uint64_t uc_mcsize;
struct __darwin_mcontext64 *uc_mcontext;
};
static void xnuexceptionstate2linux(
mcontext_t *mc, struct __darwin_x86_exception_state64 *xnues) {
mc->trapno = xnues->__trapno;
mc->err = xnues->__err;
}
static void xnuthreadstate2linux(ucontext_t *uc, mcontext_t *mc,
struct __darwin_x86_thread_state64 *xnuss) {
mc->rdi = xnuss->__rdi;
mc->rsi = xnuss->__rsi;
mc->rbp = xnuss->__rbp;
mc->rbx = xnuss->__rbx;
mc->rdx = xnuss->__rdx;
mc->rax = xnuss->__rax;
mc->rcx = xnuss->__rcx;
mc->rsp = xnuss->__rsp;
mc->rip = xnuss->__rip;
/* g.uc.uc_mcontext.rip = xnuctx->uc_mcontext->__es.__faultvaddr; */
mc->cs = xnuss->__cs;
mc->gs = xnuss->__gs;
mc->fs = xnuss->__fs;
mc->eflags = xnuss->__rflags;
uc->uc_flags = xnuss->__rflags;
memcpy(&mc->r8, &xnuss->__r8, 8 * sizeof(int64_t));
}
static void xnussefpustate2linux(struct FpuState *fs,
struct __darwin_x86_float_state64 *xnufs) {
memcpy(&fs->cwd, &xnufs->__fpu_fcw, 2);
memcpy(&fs->swd, &xnufs->__fpu_fsw, 2);
fs->ftw = xnufs->__fpu_ftw;
fs->fop = xnufs->__fpu_fop;
fs->rip = xnufs->__fpu_ip;
fs->rdp = xnufs->__fpu_dp;
fs->mxcsr = xnufs->__fpu_mxcsr;
fs->mxcr_mask = xnufs->__fpu_mxcsrmask;
/* copy st0-st7 as well as xmm0-xmm15 */
memcpy(fs->st, &xnufs->__fpu_stmm0, (8 + 16) * sizeof(uint128_t));
}
wontreturn void xnutrampoline(void *fn, int infostyle, int sig,
const struct __darwin_siginfo *xnuinfo,
const struct __darwin_ucontext *xnuctx) {
/* note: this function impl can't access static memory */
intptr_t ax;
struct Goodies {
ucontext_t uc;
siginfo_t si;
} g;
memset(&g, 0, sizeof(g));
if (xnuctx) {
/* g.uc.uc_sigmask = xnuctx->uc_sigmask; */
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
if (xnuctx->uc_mcontext) {
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_x86_exception_state64)) {
xnuexceptionstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__es);
}
if (xnuctx->uc_mcsize >= (sizeof(struct __darwin_x86_exception_state64) +
sizeof(struct __darwin_x86_thread_state64))) {
xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext,
&xnuctx->uc_mcontext->__ss);
}
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
xnussefpustate2linux(&g.uc.fpustate, &xnuctx->uc_mcontext->__fs);
}
}
}
if (xnuinfo) {
g.si.si_signo = xnuinfo->si_signo;
g.si.si_errno = xnuinfo->si_errno;
g.si.si_code = xnuinfo->si_code;
if (xnuinfo->si_pid) {
g.si.si_pid = xnuinfo->si_pid;
g.si.si_uid = xnuinfo->si_uid;
g.si.si_status = xnuinfo->si_status;
} else {
g.si.si_addr = (void *)xnuinfo->si_addr;
}
}
__sigenter(sig, &g.si, &g.uc);
asm volatile("syscall"
: "=a"(ax)
: "0"(0x20000b8 /* sigreturn */), "D"(xnuctx), "S"(infostyle)
: "rcx", "r11", "memory", "cc");
unreachable;
}