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:
Thomas A 2020-07-04 17:08:17 -07:00
parent 18cfca7dbd
commit c1745ef85a
3 changed files with 262 additions and 60 deletions

View File

@ -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

View File

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

View File

@ -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)