Commit c7a717c1 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Andrei Vagin

compel: Save and restore regs inside compel by default

CRIU keeps all registers on CoreEntry and makes sigframe from
them as well, which means anyone using the compel library
have to provide own handlers, which is inconvenient. So
now it's possible to leave this task for libcompel itself:
it will save the regs and prerare sigframe on its own.

travis-ci: success for compel: Contrinue improving library
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 3e7627c6
...@@ -7,6 +7,7 @@ COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $( ...@@ -7,6 +7,7 @@ COMPEL_SO_VERSION_CODE := $(shell expr $(COMPEL_SO_VERSION_MAJOR) \* 65536 \+ $(
ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include ccflags-y += -iquote compel/arch/$(ARCH)/src/lib/include
ccflags-y += -iquote compel/include ccflags-y += -iquote compel/include
ccflags-y += -iquote compel/plugins/include ccflags-y += -iquote compel/plugins/include
ccflags-y += -fno-strict-aliasing
ccflags-y += -fPIC ccflags-y += -fPIC
# #
......
...@@ -27,6 +27,35 @@ static inline void __always_unused __check_code_syscall(void) ...@@ -27,6 +27,35 @@ static inline void __always_unused __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
} }
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
struct fpsimd_context *fpsimd = RT_SIGFRAME_FPU(sigframe);
memcpy(sigframe->uc.uc_mcontext.regs, regs->regs, sizeof(regs->regs));
sigframe->uc.uc_mcontext.sp = regs->sp;
sigframe->uc.uc_mcontext.pc = regs->pc;
sigframe->uc.uc_mcontext.pstate = regs->pstate;
memcpy(fpsimd->vregs, fpregs->vregs, 32 * sizeof(__uint128_t));
fpsimd->fpsr = fpregs->fpsr;
fpsimd->fpcr = fpregs->fpcr;
fpsimd->head.magic = FPSIMD_MAGIC;
fpsimd->head.size = sizeof(*fpsimd);
return 0;
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe)
{
return 0;
}
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{ {
struct iovec iov; struct iovec iov;
......
...@@ -26,6 +26,44 @@ static inline __always_unused void __check_code_syscall(void) ...@@ -26,6 +26,44 @@ static inline __always_unused void __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
} }
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
struct aux_sigframe *aux = (struct aux_sigframe *)(void *)&sigframe->sig.uc.uc_regspace;
sigframe->sig.uc.uc_mcontext.arm_r0 = regs->ARM_r0;
sigframe->sig.uc.uc_mcontext.arm_r1 = regs->ARM_r1;
sigframe->sig.uc.uc_mcontext.arm_r2 = regs->ARM_r2;
sigframe->sig.uc.uc_mcontext.arm_r3 = regs->ARM_r3;
sigframe->sig.uc.uc_mcontext.arm_r4 = regs->ARM_r4;
sigframe->sig.uc.uc_mcontext.arm_r5 = regs->ARM_r5;
sigframe->sig.uc.uc_mcontext.arm_r6 = regs->ARM_r6;
sigframe->sig.uc.uc_mcontext.arm_r7 = regs->ARM_r7;
sigframe->sig.uc.uc_mcontext.arm_r8 = regs->ARM_r8;
sigframe->sig.uc.uc_mcontext.arm_r9 = regs->ARM_r9;
sigframe->sig.uc.uc_mcontext.arm_r10 = regs->ARM_r10;
sigframe->sig.uc.uc_mcontext.arm_fp = regs->ARM_fp;
sigframe->sig.uc.uc_mcontext.arm_ip = regs->ARM_ip;
sigframe->sig.uc.uc_mcontext.arm_sp = regs->ARM_sp;
sigframe->sig.uc.uc_mcontext.arm_lr = regs->ARM_lr;
sigframe->sig.uc.uc_mcontext.arm_pc = regs->ARM_pc;
sigframe->sig.uc.uc_mcontext.arm_cpsr = regs->ARM_cpsr;
memcpy(&aux->vfp.ufp.fpregs, &fpregs->fpregs, sizeof(aux->vfp.ufp.fpregs));
aux->vfp.ufp.fpscr = fpregs->fpscr;
aux->vfp.magic = VFP_MAGIC;
aux->vfp.size = VFP_STORAGE_SIZE;
return 0;
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe)
{
return 0;
}
#define PTRACE_GETVFPREGS 27 #define PTRACE_GETVFPREGS 27
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{ {
......
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/user.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <compel/plugins/std/syscall-codes.h> #include <compel/plugins/std/syscall-codes.h>
...@@ -33,6 +34,130 @@ static inline void __check_code_syscall(void) ...@@ -33,6 +34,130 @@ static inline void __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
} }
static void prep_gp_regs(mcontext_t *dst, user_regs_struct_t *regs)
{
memcpy(dst->gp_regs, regs->gpr, sizeof(regs->gpr));
dst->gp_regs[PT_NIP] = regs->nip;
dst->gp_regs[PT_MSR] = regs->msr;
dst->gp_regs[PT_ORIG_R3] = regs->orig_gpr3;
dst->gp_regs[PT_CTR] = regs->ctr;
dst->gp_regs[PT_LNK] = regs->link;
dst->gp_regs[PT_XER] = regs->xer;
dst->gp_regs[PT_CCR] = regs->ccr;
dst->gp_regs[PT_TRAP] = regs->trap;
}
static void put_fpu_regs(mcontext_t *mc, uint64_t *fpregs)
{
uint64_t *mcfp = (uint64_t *)mc->fp_regs;
memcpy(mcfp, fpregs, sizeof(*fpregs) * NFPREG);
}
static void put_altivec_regs(mcontext_t *mc, __vector128 *vrregs)
{
vrregset_t *v_regs = (vrregset_t *)(((unsigned long)mc->vmx_reserve + 15) & ~0xful);
memcpy(&v_regs->vrregs[0][0], vrregs, sizeof(uint64_t) * 2 * (NVRREG - 1));
v_regs->vrsave = *((uint32_t *)&vrregs[NVRREG - 1]);
mc->v_regs = v_regs;
}
static void put_vsx_regs(mcontext_t *mc, uint64_t *vsxregs)
{
memcpy((uint64_t *)(mc->v_regs + 1), vsxregs, sizeof(*vsxregs) * NVSXREG);
}
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
mcontext_t *dst_tc = &sigframe->uc_transact.uc_mcontext;
mcontext_t *dst = &sigframe->uc.uc_mcontext;
if (fpregs->flags & USER_FPREGS_FL_TM) {
prep_gp_regs(&sigframe->uc_transact.uc_mcontext, &fpregs->tm.regs);
prep_gp_regs(&sigframe->uc.uc_mcontext, &fpregs->tm.regs);
} else {
prep_gp_regs(&sigframe->uc.uc_mcontext, regs);
}
if (fpregs->flags & USER_FPREGS_FL_TM)
sigframe->uc.uc_link = &sigframe->uc_transact;
if (fpregs->flags & USER_FPREGS_FL_FP) {
if (fpregs->flags & USER_FPREGS_FL_TM) {
put_fpu_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.fpregs);
put_fpu_regs(&sigframe->uc.uc_mcontext, fpregs->tm.fpregs);
} else {
put_fpu_regs(&sigframe->uc.uc_mcontext, fpregs->fpregs);
}
}
if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) {
if (fpregs->flags & USER_FPREGS_FL_TM) {
put_altivec_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.vrregs);
put_altivec_regs(&sigframe->uc.uc_mcontext, fpregs->tm.vrregs);
dst_tc->gp_regs[PT_MSR] |= MSR_VEC;
} else {
put_altivec_regs(&sigframe->uc.uc_mcontext, fpregs->vrregs);
}
dst->gp_regs[PT_MSR] |= MSR_VEC;
if (fpregs->flags & USER_FPREGS_FL_VSX) {
if (fpregs->flags & USER_FPREGS_FL_TM) {
put_vsx_regs(&sigframe->uc_transact.uc_mcontext, fpregs->tm.vsxregs);
put_vsx_regs(&sigframe->uc.uc_mcontext, fpregs->tm.vsxregs);
dst_tc->gp_regs[PT_MSR] |= MSR_VSX;
} else {
put_vsx_regs(&sigframe->uc.uc_mcontext, fpregs->vsxregs);
}
dst->gp_regs[PT_MSR] |= MSR_VSX;
}
}
return 0;
}
static void update_vregs(mcontext_t *lcontext, mcontext_t *rcontext)
{
if (lcontext->v_regs) {
uint64_t offset = (uint64_t)(lcontext->v_regs) - (uint64_t)lcontext;
lcontext->v_regs = (vrregset_t *)((uint64_t)rcontext + offset);
pr_debug("Updated v_regs:%llx (rcontext:%llx)\n",
(unsigned long long)lcontext->v_regs,
(unsigned long long)rcontext);
}
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *frame,
struct rt_sigframe *rframe)
{
uint64_t msr = frame->uc.uc_mcontext.gp_regs[PT_MSR];
update_vregs(&frame->uc.uc_mcontext, &rframe->uc.uc_mcontext);
/* Sanity check: If TM so uc_link should be set, otherwise not */
if (MSR_TM_ACTIVE(msr) ^ (!!(frame->uc.uc_link))) {
BUG();
return -1;
}
/* Updating the transactional state address if any */
if (frame->uc.uc_link) {
update_vregs(&frame->uc_transact.uc_mcontext,
&rframe->uc_transact.uc_mcontext);
frame->uc.uc_link = &rframe->uc_transact;
}
return 0;
}
/* This is the layout of the POWER7 VSX registers and the way they /* This is the layout of the POWER7 VSX registers and the way they
* overlap with the existing FPR and VMX registers. * overlap with the existing FPR and VMX registers.
* *
......
...@@ -47,6 +47,87 @@ static inline __always_unused void __check_code_syscall(void) ...@@ -47,6 +47,87 @@ static inline __always_unused void __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall))); BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
} }
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
bool is_native = user_regs_native(regs);
fpu_state_t *fpu_state = is_native ?
&sigframe->native.fpu_state :
&sigframe->compat.fpu_state;
if (is_native) {
#define cpreg64_native(d, s) sigframe->native.uc.uc_mcontext.d = regs->native.s
cpreg64_native(rdi, di);
cpreg64_native(rsi, si);
cpreg64_native(rbp, bp);
cpreg64_native(rsp, sp);
cpreg64_native(rbx, bx);
cpreg64_native(rdx, dx);
cpreg64_native(rcx, cx);
cpreg64_native(rip, ip);
cpreg64_native(rax, ax);
cpreg64_native(r8, r8);
cpreg64_native(r9, r9);
cpreg64_native(r10, r10);
cpreg64_native(r11, r11);
cpreg64_native(r12, r12);
cpreg64_native(r13, r13);
cpreg64_native(r14, r14);
cpreg64_native(r15, r15);
cpreg64_native(cs, cs);
cpreg64_native(eflags, flags);
sigframe->is_native = true;
#undef cpreg64_native
} else {
#define cpreg32_compat(d) sigframe->compat.uc.uc_mcontext.d = regs->compat.d
cpreg32_compat(gs);
cpreg32_compat(fs);
cpreg32_compat(es);
cpreg32_compat(ds);
cpreg32_compat(di);
cpreg32_compat(si);
cpreg32_compat(bp);
cpreg32_compat(sp);
cpreg32_compat(bx);
cpreg32_compat(dx);
cpreg32_compat(cx);
cpreg32_compat(ip);
cpreg32_compat(ax);
cpreg32_compat(cs);
cpreg32_compat(ss);
cpreg32_compat(flags);
#undef cpreg32_compat
sigframe->is_native = false;
}
fpu_state->has_fpu = true;
memcpy(&fpu_state->xsave, fpregs, sizeof(*fpregs));
return 0;
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe)
{
fpu_state_t *fpu_state = (sigframe->is_native) ?
&rsigframe->native.fpu_state :
&rsigframe->compat.fpu_state;
unsigned long addr = (unsigned long)(void *)&fpu_state->xsave;
if (sigframe->is_native && (addr % 64ul) == 0ul) {
sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave;
} else if (!sigframe->is_native && (addr % 32ul) == 0ul) {
sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr;
} else {
pr_err("Unaligned address passed: %lx (native %d)\n",
addr, sigframe->is_native);
return -1;
}
return 0;
}
#define get_signed_user_reg(pregs, name) \ #define get_signed_user_reg(pregs, name) \
((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \
(int32_t)((pregs)->compat.name)) (int32_t)((pregs)->compat.name))
......
...@@ -67,5 +67,9 @@ extern void *remote_mmap(struct parasite_ctl *ctl, ...@@ -67,5 +67,9 @@ extern void *remote_mmap(struct parasite_ctl *ctl,
int flags, int fd, off_t offset); int flags, int fd, off_t offset);
extern bool arch_can_dump_task(struct parasite_ctl *ctl); extern bool arch_can_dump_task(struct parasite_ctl *ctl);
extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg); extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg);
extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe,
user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs);
extern int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe);
#endif #endif
...@@ -1008,6 +1008,58 @@ static void handle_sigchld(int signal, siginfo_t *siginfo, void *data) ...@@ -1008,6 +1008,58 @@ static void handle_sigchld(int signal, siginfo_t *siginfo, void *data)
/* FIXME -- what to do here? */ /* FIXME -- what to do here? */
} }
struct plain_regs_struct {
user_regs_struct_t regs;
user_fpregs_struct_t fpregs;
};
static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t *f)
{
struct plain_regs_struct *prs = to;
prs->regs = *r;
prs->fpregs = *f;
return 0;
}
#ifndef RT_SIGFRAME_UC_SIGMASK
#define RT_SIGFRAME_UC_SIGMASK(sigframe) \
(k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask
#endif
static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigframe *rtf, k_rtsigset_t *b)
{
struct plain_regs_struct *prs = from;
k_rtsigset_t *blk_sigset;
/*
* Make sure it's zeroified.
*/
memset(f, 0, sizeof(*f));
if (sigreturn_prep_regs_plain(f, &prs->regs, &prs->fpregs))
return -1;
blk_sigset = RT_SIGFRAME_UC_SIGMASK(f);
if (b)
memcpy(blk_sigset, b, sizeof(k_rtsigset_t));
else
memset(blk_sigset, 0, sizeof(k_rtsigset_t));
if (RT_SIGFRAME_HAS_FPU(f)) {
if (sigreturn_prep_fpu_frame_plain(f, rtf))
return -1;
}
/*
* FIXME What about sas?
* setup_sas(sigframe, core->thread_core->sas);
*/
return 0;
}
struct parasite_ctl *compel_prepare(int pid) struct parasite_ctl *compel_prepare(int pid)
{ {
struct parasite_ctl *ctl; struct parasite_ctl *ctl;
...@@ -1024,6 +1076,12 @@ struct parasite_ctl *compel_prepare(int pid) ...@@ -1024,6 +1076,12 @@ struct parasite_ctl *compel_prepare(int pid)
ictx->child_handler = handle_sigchld; ictx->child_handler = handle_sigchld;
sigaction(SIGCHLD, NULL, &ictx->orig_handler); sigaction(SIGCHLD, NULL, &ictx->orig_handler);
ictx->save_regs = save_regs_plain;
ictx->make_sigframe = make_sigframe_plain;
ictx->regs_arg = xmalloc(sizeof(struct plain_regs_struct));
if (ictx->regs_arg == NULL)
goto err;
if (ictx->syscall_ip == (unsigned long)MAP_FAILED) if (ictx->syscall_ip == (unsigned long)MAP_FAILED)
goto err; goto err;
ictx->sock = make_sock_for(pid); ictx->sock = make_sock_for(pid);
...@@ -1034,6 +1092,7 @@ out: ...@@ -1034,6 +1092,7 @@ out:
return ctl; return ctl;
err: err:
free(ictx->regs_arg);
free(ctl); free(ctl);
goto out; goto out;
} }
......
...@@ -49,8 +49,8 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) ...@@ -49,8 +49,8 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs)
static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe) static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe)
{ {
int i;
uint64_t *mcfp = (uint64_t *)mc->fp_regs; uint64_t *mcfp = (uint64_t *)mc->fp_regs;
size_t i;
for (i = 0; i < fpe->n_fpregs; i++) for (i = 0; i < fpe->n_fpregs; i++)
mcfp[i] = fpe->fpregs[i]; mcfp[i] = fpe->fpregs[i];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment