mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-26 22:00:29 +00:00
src/kernel/emulation/linux: Implement Signal Support for ARM64
Note, I am not sure if some of the changes I made were correct.
This commit is contained in:
parent
18cfca7dbd
commit
c1745ef85a
@ -181,17 +181,26 @@ static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_uc
|
||||
bc->uc_stack.ss_size = lc->uc_stack.ss_size;
|
||||
bc->uc_stack.ss_sp = lc->uc_stack.ss_sp;
|
||||
|
||||
bm->es.trapno = lc->uc_mcontext.gregs.trapno;
|
||||
bm->es.cpu = 0;
|
||||
bm->es.err = lc->uc_mcontext.gregs.err;
|
||||
#ifdef __x86_64__
|
||||
bm->es.faultvaddr = lc->uc_mcontext.gregs.rip;
|
||||
#else
|
||||
bm->es.faultvaddr = lc->uc_mcontext.gregs.eip;
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
bm->es.trapno = lc->uc_mcontext.gregs.trapno;
|
||||
bm->es.cpu = 0;
|
||||
bm->es.err = lc->uc_mcontext.gregs.err;
|
||||
#ifdef __x86_64__
|
||||
bm->es.faultvaddr = lc->uc_mcontext.gregs.rip;
|
||||
#else
|
||||
bm->es.faultvaddr = lc->uc_mcontext.gregs.eip;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef copyreg
|
||||
#undef copyreg2
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#define copyreg(__name) bm->ss.__name = lc->uc_mcontext.gregs.__name
|
||||
#elif defined(__arm64__)
|
||||
#define copyreg(__name) bm->ss.__name = lc->uc_mcontext.__name
|
||||
#define copyreg2(__nameA, __nameB) bm->ss.__nameA = lc->uc_mcontext.__nameB
|
||||
#endif
|
||||
|
||||
#define copyreg(__name) bm->ss.__name = lc->uc_mcontext.gregs.__name
|
||||
|
||||
#ifdef __x86_64__
|
||||
copyreg(rax); copyreg(rbx); copyreg(rcx); copyreg(rdx); copyreg(rdi); copyreg(rsi);
|
||||
copyreg(rbp); copyreg(rsp); copyreg(r8); copyreg(r9); copyreg(r10);
|
||||
@ -205,6 +214,15 @@ static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_uc
|
||||
copyreg(eip); copyreg(cs); copyreg(ds); copyreg(es); copyreg(fs); copyreg(gs);
|
||||
bm->ss.eflags = lc->uc_mcontext.gregs.efl;
|
||||
bm->ss.ss = 0;
|
||||
#elif defined(__arm64__)
|
||||
memcpy(bm->ss.x, lc->uc_mcontext.regs, sizeof(bm->ss.x));
|
||||
copyreg2(fp, regs[29]); copyreg2(lr, regs[30]);
|
||||
copyreg(sp); copyreg(pc);
|
||||
|
||||
// I'm unsure about this...
|
||||
bm->ss.cpsr = lc->uc_mcontext.pstate;
|
||||
bm->ss.__pad = lc->uc_mcontext.pstate >> 32;
|
||||
bm->es.faultvaddr = lc->uc_mcontext.fault_address;
|
||||
#else
|
||||
# warning Missing code for current arch
|
||||
#endif
|
||||
@ -214,7 +232,14 @@ static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_uc
|
||||
|
||||
static void mcontext_bsd_to_linux(const struct bsd_mcontext* bm, struct linux_mcontext* lm)
|
||||
{
|
||||
#define copyreg(__name) lm->gregs.__name = bm->ss.__name
|
||||
#undef copyreg
|
||||
#undef copyreg2
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#define copyreg(__name) lm->gregs.__name = bm->ss.__name
|
||||
#elif defined(__arm64__)
|
||||
#define copyreg(__name) lm->__name = bm->ss.__name
|
||||
#define copyreg2(__nameA, __nameB) lm->__nameA = bm->ss.__nameB
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
copyreg(rax); copyreg(rbx); copyreg(rcx); copyreg(rdx); copyreg(rdi); copyreg(rsi);
|
||||
@ -227,6 +252,15 @@ static void mcontext_bsd_to_linux(const struct bsd_mcontext* bm, struct linux_mc
|
||||
copyreg(ebp); copyreg(esp);
|
||||
copyreg(eip); copyreg(cs); copyreg(ds); copyreg(es); copyreg(fs); copyreg(gs);
|
||||
lm->gregs.efl = bm->ss.eflags;
|
||||
#elif defined(__arm64__)
|
||||
memcpy(lm->regs, bm->ss.x, sizeof(bm->ss.x));
|
||||
copyreg2(regs[29], fp); copyreg2(regs[30], lr);
|
||||
copyreg(sp); copyreg(pc);
|
||||
|
||||
// I am not so sure about these
|
||||
lm->pstate = bm->ss.cpsr;
|
||||
lm->pstate |= (unsigned long long int) bm->ss.__pad << 32;
|
||||
lm->fault_address = bm->es.faultvaddr;
|
||||
#else
|
||||
# warning Missing code for current arch
|
||||
#endif
|
||||
|
@ -36,7 +36,7 @@ struct bsd_siginfo
|
||||
};
|
||||
|
||||
# define __SI_MAX_SIZE 128
|
||||
# if defined (__x86_64__)
|
||||
# ifdef __LP64__
|
||||
# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 4)
|
||||
# else
|
||||
# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 3)
|
||||
@ -103,35 +103,40 @@ struct linux_sigaction
|
||||
long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa);
|
||||
|
||||
#ifdef __x86_64__
|
||||
typedef struct _fpstate {
|
||||
unsigned short cwd, swd, ftw, fop;
|
||||
unsigned long long rip, rdp;
|
||||
unsigned mxcsr, mxcr_mask;
|
||||
struct {
|
||||
unsigned short significand[4], exponent, padding[3];
|
||||
} _st[8];
|
||||
struct {
|
||||
unsigned element[4];
|
||||
} _xmm[16];
|
||||
unsigned padding[24];
|
||||
} *linux_fpregset_t;
|
||||
// #include <asm/sigcontext.h>
|
||||
// struct _fpstate_64 { ... };
|
||||
typedef struct _fpstate {
|
||||
unsigned short cwd, swd, ftw, fop;
|
||||
unsigned long long rip, rdp;
|
||||
unsigned mxcsr, mxcr_mask;
|
||||
struct {
|
||||
unsigned short significand[4], exponent, padding[3];
|
||||
} _st[8];
|
||||
struct {
|
||||
unsigned element[4];
|
||||
} _xmm[16];
|
||||
unsigned padding[24];
|
||||
} *linux_fpregset_t;
|
||||
|
||||
struct linux_gregset
|
||||
{
|
||||
long long r8, r9, r10, r11, r12, r13, r14, r15, rdi, rsi, rbp, rbx;
|
||||
long long rdx, rax, rcx, rsp, rip, efl;
|
||||
short cs, gs, fs, __pad0;
|
||||
long long err, trapno, oldmask, cr2;
|
||||
};
|
||||
// #include <sys/user.h>
|
||||
// struct user_regs_struct { ... };
|
||||
struct linux_gregset
|
||||
{
|
||||
long long r8, r9, r10, r11, r12, r13, r14, r15, rdi, rsi, rbp, rbx;
|
||||
long long rdx, rax, rcx, rsp, rip, efl;
|
||||
short cs, gs, fs, __pad0;
|
||||
long long err, trapno, oldmask, cr2;
|
||||
};
|
||||
|
||||
#else // now the i386 version
|
||||
|
||||
typedef struct _fpstate {
|
||||
unsigned long cw, sw, tag, ipoff, cssel, dataoff, datasel;
|
||||
struct {
|
||||
unsigned short significand[4], exponent;
|
||||
} _st[8];
|
||||
unsigned short status, magic;
|
||||
#elif defined(__i386__)
|
||||
// #include <asm/sigcontext.h>
|
||||
// struct _fpstate_32 { ... };
|
||||
typedef struct _fpstate {
|
||||
unsigned long cw, sw, tag, ipoff, cssel, dataoff, datasel;
|
||||
struct {
|
||||
unsigned short significand[4], exponent;
|
||||
} _st[8];
|
||||
unsigned short status, magic;
|
||||
unsigned int _fxsr_env[6];
|
||||
unsigned int mxcsr;
|
||||
unsigned int reserved;
|
||||
@ -140,39 +145,82 @@ typedef struct _fpstate {
|
||||
unsigned short exponent;
|
||||
unsigned short padding[3];
|
||||
} _fxsr_st[8];
|
||||
struct {
|
||||
unsigned element[4];
|
||||
} _xmm[8];
|
||||
} *linux_fpregset_t;
|
||||
struct {
|
||||
unsigned element[4];
|
||||
} _xmm[8];
|
||||
} *linux_fpregset_t;
|
||||
|
||||
struct linux_gregset
|
||||
{
|
||||
int gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
int trapno, err, eip, cs, efl, uesp;
|
||||
int ss;
|
||||
};
|
||||
#endif
|
||||
// #include <asm/sigcontext.h>
|
||||
// struct sigcontext_32 { ... }; ?
|
||||
struct linux_gregset
|
||||
{
|
||||
int gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
int trapno, err, eip, cs, efl, uesp;
|
||||
int ss;
|
||||
};
|
||||
|
||||
struct linux_mcontext
|
||||
{
|
||||
struct linux_gregset gregs;
|
||||
linux_fpregset_t fpregs;
|
||||
#ifdef __x86_64__
|
||||
unsigned long long __reserved[8];
|
||||
#elif defined(__arm64__)
|
||||
// #include <asm/sigcontext.h>
|
||||
// struct _aarch64_ctx { ... };
|
||||
struct linux_aarch64_ctx {
|
||||
__uint32_t magic;
|
||||
__uint32_t size;
|
||||
};
|
||||
|
||||
#define FPSIMD_MAGIC 0x46508001
|
||||
|
||||
// #include <asm/sigcontext.h>
|
||||
// struct fpsimd_context { ... }
|
||||
struct linux_fpsimd_context {
|
||||
struct linux_aarch64_ctx head;
|
||||
__uint32_t fpsr;
|
||||
__uint32_t fpcr;
|
||||
__uint128_t vregs[32];
|
||||
};
|
||||
#else
|
||||
unsigned long oldmask, cr2;
|
||||
#error "Floating point registers not defined"
|
||||
#endif
|
||||
|
||||
// #include <sys/ucontext.h>
|
||||
// typedef struct { ... } mcontext_t;
|
||||
struct linux_mcontext
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
struct linux_gregset gregs;
|
||||
linux_fpregset_t fpregs;
|
||||
#ifdef __x86_64__
|
||||
unsigned long long __reserved[8];
|
||||
#else
|
||||
unsigned long oldmask, cr2;
|
||||
#endif
|
||||
#elif defined(__arm64__)
|
||||
unsigned long long int fault_address;
|
||||
unsigned long long int regs[31];
|
||||
unsigned long long int sp;
|
||||
unsigned long long int pc;
|
||||
unsigned long long int pstate;
|
||||
unsigned char __reserved[4096] __attribute__ ((__aligned__ (16)));
|
||||
#else
|
||||
#error "linux_mcontext not defined"
|
||||
#endif
|
||||
// +reserved
|
||||
};
|
||||
|
||||
// #include <sys/ucontext.h>
|
||||
// typedef struct ucontext_t { ... } ucontext_t;
|
||||
struct linux_ucontext
|
||||
{
|
||||
unsigned long uc_flags;
|
||||
struct linux_ucontext* uc_link;
|
||||
struct linux_stack uc_stack;
|
||||
struct linux_mcontext uc_mcontext;
|
||||
linux_sigset_t uc_sigmask;
|
||||
// linux_libc_fpstate fpregs_mem;
|
||||
#if defined(__x64_64__) || defined(__i386__)
|
||||
struct linux_mcontext uc_mcontext;
|
||||
linux_sigset_t uc_sigmask;
|
||||
// linux_libc_fpstate fpregs_mem;
|
||||
#else //defined(__arm64__)
|
||||
linux_sigset_t uc_sigmask;
|
||||
struct linux_mcontext uc_mcontext;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bsd_exception_state
|
||||
@ -188,9 +236,15 @@ struct bsd_thread_state
|
||||
#ifdef __x86_64__
|
||||
long long rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp, r8, r9, r10;
|
||||
long long r11, r12, r13, r14, r15, rip, rflags, cs, fs, gs;
|
||||
#else
|
||||
#elif defined(__i386__)
|
||||
int eax, ebx, ecx, edx, edi, esi, ebp, esp, ss, eflags;
|
||||
int eip, cs, ds, es, fs, gs;
|
||||
#elif defined(__arm64__)
|
||||
__uint64_t x[29];
|
||||
__uint64_t fp, lr, sp, pc;
|
||||
__uint32_t cpsr, __pad;
|
||||
#else
|
||||
#error "Architecture registers are missing in bsd_thread_state"
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,11 @@ static void mcontext_to_thread_state(const struct linux_gregset* regs, x86_threa
|
||||
static void mcontext_to_float_state(const linux_fpregset_t fx, x86_float_state32_t* s);
|
||||
static void thread_state_to_mcontext(const x86_thread_state32_t* s, struct linux_gregset* regs);
|
||||
static void float_state_to_mcontext(const x86_float_state32_t* s, linux_fpregset_t fx);
|
||||
#elif defined(__arm64__)
|
||||
void mcontext_to_thread_state(const struct linux_mcontext* context, arm_thread_state64_t* state);
|
||||
void mcontext_to_float_state(const struct linux_mcontext* context, arm_neon_state64_t* state);
|
||||
void thread_state_to_mcontext(const arm_thread_state64_t* state, struct linux_mcontext* context);
|
||||
void float_state_to_mcontext(const arm_neon_state64_t* state, struct linux_mcontext* context);
|
||||
#endif
|
||||
|
||||
static void state_from_kernel(struct linux_ucontext* ctxt, const struct thread_state* kernel_state);
|
||||
@ -126,6 +131,9 @@ void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt)
|
||||
#elif defined(__i386__)
|
||||
x86_thread_state32_t tstate;
|
||||
x86_float_state32_t fstate;
|
||||
#elif defined(__arm64__)
|
||||
arm_thread_state64_t tstate;
|
||||
arm_neon_state64_t fstate;
|
||||
#endif
|
||||
|
||||
struct thread_suspended_args args;
|
||||
@ -186,6 +194,11 @@ static void state_to_kernel(struct linux_ucontext* ctxt, struct thread_state* ke
|
||||
#elif defined(__i386__)
|
||||
mcontext_to_thread_state(&ctxt->uc_mcontext.gregs, (x86_thread_state32_t*) kernel_state->tstate);
|
||||
mcontext_to_float_state(ctxt->uc_mcontext.fpregs, (x86_float_state32_t*) kernel_state->fstate);
|
||||
|
||||
#elif defined(__arm64__)
|
||||
mcontext_to_thread_state(&ctxt->uc_mcontext, (arm_thread_state64_t*) kernel_state->tstate);
|
||||
mcontext_to_float_state(&ctxt->uc_mcontext, (arm_neon_state64_t*) kernel_state->fstate);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -202,6 +215,11 @@ static void state_from_kernel(struct linux_ucontext* ctxt, const struct thread_s
|
||||
#elif defined(__i386__)
|
||||
thread_state_to_mcontext((x86_thread_state32_t*) kernel_state->tstate, &ctxt->uc_mcontext.gregs);
|
||||
float_state_to_mcontext((x86_float_state32_t*) kernel_state->fstate, ctxt->uc_mcontext.fpregs);
|
||||
|
||||
#elif defined(__arm64__)
|
||||
thread_state_to_mcontext((arm_thread_state64_t*) kernel_state->tstate, &ctxt->uc_mcontext);
|
||||
float_state_to_mcontext((arm_neon_state64_t*) kernel_state->fstate, &ctxt->uc_mcontext);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -237,6 +255,9 @@ void sigexc_handler(int linux_signum, struct linux_siginfo* info, struct linux_u
|
||||
#elif defined(__i386__)
|
||||
x86_thread_state32_t tstate;
|
||||
x86_float_state32_t fstate;
|
||||
#elif defined(__arm64__)
|
||||
arm_thread_state64_t tstate;
|
||||
arm_neon_state64_t fstate;
|
||||
#endif
|
||||
|
||||
sigprocess.state.tstate = &tstate;
|
||||
@ -488,6 +509,99 @@ void float_state_to_mcontext(const x86_float_state32_t* s, linux_fpregset_t fx)
|
||||
memcpy(fx->_st, &s->__fpu_stmm0, 128);
|
||||
memcpy(fx->_xmm, &s->__fpu_xmm0, 128);
|
||||
}
|
||||
|
||||
#elif defined(__arm64__)
|
||||
void mcontext_to_thread_state(const struct linux_mcontext* context, arm_thread_state64_t* state)
|
||||
{
|
||||
memcpy(state->__x, context->regs, sizeof(state->__x));
|
||||
state->__fp = context->regs[29];
|
||||
state->__lr = context->regs[30];
|
||||
state->__sp = context->sp;
|
||||
state->__pc = context->pc;
|
||||
|
||||
// I am not sure if this is actually correct...
|
||||
state->__cpsr = (__uint32_t) context->pstate;
|
||||
state->__pad = (__uint32_t) (context->pstate >> 32);
|
||||
}
|
||||
|
||||
void mcontext_to_float_state(const struct linux_mcontext* context, arm_neon_state64_t* state)
|
||||
{
|
||||
unsigned char const *ptr = context->__reserved;
|
||||
int index = 0;
|
||||
while (index + sizeof(struct linux_aarch64_ctx) < 4096) {
|
||||
struct linux_aarch64_ctx *ctx = (struct linux_aarch64_ctx *) (ptr + index);
|
||||
|
||||
// (1) Avoid an infinite loop by checking if the size is zero
|
||||
// (2) Make sure that index + size doesn't excede array
|
||||
if (ctx->size == 0 || index + ctx->size < 4096) {
|
||||
break;
|
||||
}
|
||||
|
||||
else if (ctx->magic == FPSIMD_MAGIC) {
|
||||
struct linux_fpsimd_context *fpsimd = (struct linux_fpsimd_context *) (ptr + index);
|
||||
state->__fpsr = fpsimd->fpsr;
|
||||
state->__fpcr = fpsimd->fpcr;
|
||||
memcpy(state->__v, fpsimd->vregs, sizeof(state->__v));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
index += ctx->size;
|
||||
}
|
||||
}
|
||||
|
||||
void thread_state_to_mcontext(const arm_thread_state64_t* state, struct linux_mcontext* context)
|
||||
{
|
||||
memcpy(context->regs, state->__x, sizeof(state->__x));
|
||||
context->regs[29] = state->__fp;
|
||||
context->regs[30] = state->__lr;
|
||||
context->sp = state->__sp;
|
||||
context->pc = state->__pc;
|
||||
|
||||
// I am not sure if this is actually correct...
|
||||
context->pstate = state->__cpsr;
|
||||
context->pstate |= (unsigned long long) state->__pad << 32;
|
||||
}
|
||||
|
||||
void float_state_to_mcontext(const arm_neon_state64_t* state, struct linux_mcontext* context)
|
||||
{
|
||||
unsigned char *ptr = context->__reserved;
|
||||
int index = 0;
|
||||
while (index + sizeof(struct linux_aarch64_ctx) < 4096) {
|
||||
struct linux_aarch64_ctx *ctx = (struct linux_aarch64_ctx *) (ptr + index);
|
||||
|
||||
// Make sure that index + size doesn't excede array
|
||||
if (index + ctx->size < 4096) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If fpsimd_context does exist, let update the values.
|
||||
else if (ctx->magic == FPSIMD_MAGIC) {
|
||||
struct linux_fpsimd_context *fpsimd = (struct linux_fpsimd_context *) (ptr + index);
|
||||
fpsimd->fpsr = state->__fpsr;
|
||||
fpsimd->fpcr = state->__fpcr;
|
||||
memcpy(fpsimd->vregs, state->__v, sizeof(state->__v));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If fpsimd_context does not exist, lets add one at the end.
|
||||
else if (ctx->size == 0) {
|
||||
if (index + sizeof(struct linux_fpsimd_context) < 4096) {
|
||||
struct linux_fpsimd_context *fpsimd = (struct linux_fpsimd_context *) (ptr + index);
|
||||
fpsimd->head.magic = FPSIMD_MAGIC;
|
||||
fpsimd->head.size = sizeof(struct linux_fpsimd_context);
|
||||
fpsimd->fpsr = state->__fpsr;
|
||||
fpsimd->fpcr = state->__fpcr;
|
||||
memcpy(fpsimd->vregs, state->__v, sizeof(state->__v));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
index += ctx->size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void sigexc_thread_setup(void)
|
||||
|
Loading…
Reference in New Issue
Block a user