diff --git a/compel/Makefile b/compel/Makefile index 27ef59c52..ad0315566 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -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/include ccflags-y += -iquote compel/plugins/include +ccflags-y += -fno-strict-aliasing ccflags-y += -fPIC # diff --git a/compel/arch/aarch64/src/lib/infect.c b/compel/arch/aarch64/src/lib/infect.c index 0fc639a1e..ee1ec7c20 100644 --- a/compel/arch/aarch64/src/lib/infect.c +++ b/compel/arch/aarch64/src/lib/infect.c @@ -27,6 +27,35 @@ static inline void __always_unused __check_code_syscall(void) 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) { struct iovec iov; diff --git a/compel/arch/arm/src/lib/infect.c b/compel/arch/arm/src/lib/infect.c index 7d9a23024..61377691a 100644 --- a/compel/arch/arm/src/lib/infect.c +++ b/compel/arch/arm/src/lib/infect.c @@ -26,6 +26,44 @@ static inline __always_unused void __check_code_syscall(void) 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 int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg) { diff --git a/compel/arch/ppc64/src/lib/infect.c b/compel/arch/ppc64/src/lib/infect.c index 1f1437414..637c3654e 100644 --- a/compel/arch/ppc64/src/lib/infect.c +++ b/compel/arch/ppc64/src/lib/infect.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,130 @@ static inline void __check_code_syscall(void) 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 * overlap with the existing FPR and VMX registers. * diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index a9a0556aa..be0439917 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -47,6 +47,87 @@ static inline __always_unused void __check_code_syscall(void) 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) \ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \ (int32_t)((pregs)->compat.name)) diff --git a/compel/include/infect-priv.h b/compel/include/infect-priv.h index 4eda1acdd..fde5548b7 100644 --- a/compel/include/infect-priv.h +++ b/compel/include/infect-priv.h @@ -67,5 +67,9 @@ extern void *remote_mmap(struct parasite_ctl *ctl, int flags, int fd, off_t offset); 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 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 diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 942cef877..4f5de2fb1 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -1008,6 +1008,58 @@ static void handle_sigchld(int signal, siginfo_t *siginfo, void *data) /* 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 *ctl; @@ -1024,6 +1076,12 @@ struct parasite_ctl *compel_prepare(int pid) ictx->child_handler = handle_sigchld; 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) goto err; ictx->sock = make_sock_for(pid); @@ -1034,6 +1092,7 @@ out: return ctl; err: + free(ictx->regs_arg); free(ctl); goto out; } diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c index 074490956..c4f0df790 100644 --- a/criu/arch/ppc64/crtools.c +++ b/criu/arch/ppc64/crtools.c @@ -49,8 +49,8 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs) static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe) { - int i; uint64_t *mcfp = (uint64_t *)mc->fp_regs; + size_t i; for (i = 0; i < fpe->n_fpregs; i++) mcfp[i] = fpe->fpregs[i];