[CRIU] [PATCH 36/78] infect: Move get_task_regs-s into arch/infect.c
Cyrill Gorcunov
gorcunov at openvz.org
Mon Nov 7 08:36:21 PST 2016
From: Pavel Emelyanov <xemul at virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
criu/arch/aarch64/crtools.c | 27 ----
criu/arch/aarch64/include/asm/dump.h | 2 -
criu/arch/aarch64/infect.c | 36 ++++++
criu/arch/arm/crtools.c | 35 ------
criu/arch/arm/include/asm/dump.h | 2 -
criu/arch/arm/infect.c | 42 +++++++
criu/arch/ppc64/crtools.c | 232 ----------------------------------
criu/arch/ppc64/include/asm/dump.h | 2 -
criu/arch/ppc64/infect.c | 238 +++++++++++++++++++++++++++++++++++
criu/arch/x86/crtools.c | 67 ----------
criu/arch/x86/include/asm/dump.h | 2 -
criu/arch/x86/infect.c | 73 +++++++++++
criu/include/infect.h | 3 +
criu/infect.c | 4 +-
criu/parasite-syscall.c | 2 +-
15 files changed, 395 insertions(+), 372 deletions(-)
diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c
index a02b63ac0a0e..b3e5e55fcee7 100644
--- a/criu/arch/aarch64/crtools.c
+++ b/criu/arch/aarch64/crtools.c
@@ -81,33 +81,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e
-int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
-{
- struct iovec iov;
- user_fpregs_struct_t fpsimd;
- int ret;
-
- pr_info("Dumping GP/FPU registers for %d\n", pid);
-
- iov.iov_base = ®s;
- iov.iov_len = sizeof(user_regs_struct_t);
- if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) {
- pr_perror("Failed to obtain CPU registers for %d", pid);
- goto err;
- }
-
- iov.iov_base = &fpsimd;
- iov.iov_len = sizeof(fpsimd);
- if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
- pr_perror("Failed to obtain FPU registers for %d", pid);
- goto err;
- }
-
- ret = save(arg, ®s, &fpsimd);
-err:
- return ret;
-}
-
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
{
int i;
diff --git a/criu/arch/aarch64/include/asm/dump.h b/criu/arch/aarch64/include/asm/dump.h
index c53f67c3d487..8a966628900b 100644
--- a/criu/arch/aarch64/include/asm/dump.h
+++ b/criu/arch/aarch64/include/asm/dump.h
@@ -1,9 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
-typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
-extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
diff --git a/criu/arch/aarch64/infect.c b/criu/arch/aarch64/infect.c
index c1c1174aaffa..92b3c73b1e48 100644
--- a/criu/arch/aarch64/infect.c
+++ b/criu/arch/aarch64/infect.c
@@ -1,5 +1,41 @@
+#include <sys/ptrace.h>
#include <sys/types.h>
+#include <sys/uio.h>
+#include <linux/elf.h>
+#include "asm/parasite-syscall.h"
+#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
+#include "criu-log.h"
+#include "kerndat.h"
#include "parasite-syscall.h"
+#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
+
+int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
+{
+ struct iovec iov;
+ user_fpregs_struct_t fpsimd;
+ int ret;
+
+ pr_info("Dumping GP/FPU registers for %d\n", pid);
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(user_regs_struct_t);
+ if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) {
+ pr_perror("Failed to obtain CPU registers for %d", pid);
+ goto err;
+ }
+
+ iov.iov_base = &fpsimd;
+ iov.iov_len = sizeof(fpsimd);
+ if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
+ pr_perror("Failed to obtain FPU registers for %d", pid);
+ goto err;
+ }
+
+ ret = save(arg, ®s, &fpsimd);
+err:
+ return ret;
+}
+
diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c
index 66a42cada9b9..fb267fe85072 100644
--- a/criu/arch/arm/crtools.c
+++ b/criu/arch/arm/crtools.c
@@ -83,41 +83,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e)
-#define PTRACE_GETVFPREGS 27
-int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
-{
- user_fpregs_struct_t vfp;
- int ret = -1;
-
- pr_info("Dumping GP/FPU registers for %d\n", pid);
-
- if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) {
- pr_perror("Can't obtain FPU registers for %d", pid);
- goto err;
- }
-
- /* Did we come from a system call? */
- if ((int)regs.ARM_ORIG_r0 >= 0) {
- /* Restart the system call */
- switch ((long)(int)regs.ARM_r0) {
- case -ERESTARTNOHAND:
- case -ERESTARTSYS:
- case -ERESTARTNOINTR:
- regs.ARM_r0 = regs.ARM_ORIG_r0;
- regs.ARM_pc -= 4;
- break;
- case -ERESTART_RESTARTBLOCK:
- regs.ARM_r0 = __NR_restart_syscall;
- regs.ARM_pc -= 4;
- break;
- }
- }
-
- ret = save(arg, ®s, &vfp);
-err:
- return ret;
-}
-
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;
diff --git a/criu/arch/arm/include/asm/dump.h b/criu/arch/arm/include/asm/dump.h
index fa83b8267710..f08e53843614 100644
--- a/criu/arch/arm/include/asm/dump.h
+++ b/criu/arch/arm/include/asm/dump.h
@@ -1,9 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
-typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
-extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
diff --git a/criu/arch/arm/infect.c b/criu/arch/arm/infect.c
index c1c1174aaffa..d524d513026f 100644
--- a/criu/arch/arm/infect.c
+++ b/criu/arch/arm/infect.c
@@ -1,5 +1,47 @@
+#include <sys/ptrace.h>
#include <sys/types.h>
+#include "asm/parasite-syscall.h"
+#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
+#include "criu-log.h"
+#include "kerndat.h"
#include "parasite-syscall.h"
+#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
+
+#define PTRACE_GETVFPREGS 27
+int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
+{
+ user_fpregs_struct_t vfp;
+ int ret = -1;
+
+ pr_info("Dumping GP/FPU registers for %d\n", pid);
+
+ if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) {
+ pr_perror("Can't obtain FPU registers for %d", pid);
+ goto err;
+ }
+
+ /* Did we come from a system call? */
+ if ((int)regs.ARM_ORIG_r0 >= 0) {
+ /* Restart the system call */
+ switch ((long)(int)regs.ARM_r0) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ regs.ARM_r0 = regs.ARM_ORIG_r0;
+ regs.ARM_pc -= 4;
+ break;
+ case -ERESTART_RESTARTBLOCK:
+ regs.ARM_r0 = __NR_restart_syscall;
+ regs.ARM_pc -= 4;
+ break;
+ }
+ }
+
+ ret = save(arg, ®s, &vfp);
+err:
+ return ret;
+}
+
diff --git a/criu/arch/ppc64/crtools.c b/criu/arch/ppc64/crtools.c
index 14d2dc70ccd2..fbcdf51497ec 100644
--- a/criu/arch/ppc64/crtools.c
+++ b/criu/arch/ppc64/crtools.c
@@ -25,15 +25,6 @@
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"
-#ifndef NT_PPC_TM_SPR
-#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
-#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
-#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
-#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
-#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
-#endif
-
-
/*
* Injected syscall instruction
*/
@@ -118,55 +109,6 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs)
return fpe;
}
-/* This is the layout of the POWER7 VSX registers and the way they
- * overlap with the existing FPR and VMX registers.
- *
- * VSR doubleword 0 VSR doubleword 1
- * ----------------------------------------------------------------
- * VSR[0] | FPR[0] | |
- * ----------------------------------------------------------------
- * VSR[1] | FPR[1] | |
- * ----------------------------------------------------------------
- * | ... | |
- * ----------------------------------------------------------------
- * VSR[30] | FPR[30] | |
- * ----------------------------------------------------------------
- * VSR[31] | FPR[31] | |
- * ----------------------------------------------------------------
- * VSR[32] | VR[0] |
- * ----------------------------------------------------------------
- * VSR[33] | VR[1] |
- * ----------------------------------------------------------------
- * | ... |
- * ----------------------------------------------------------------
- * VSR[62] | VR[30] |
- * ----------------------------------------------------------------
- * VSR[63] | VR[31] |
- * ----------------------------------------------------------------
- *
- * PTRACE_GETFPREGS returns FPR[0..31] + FPSCR
- * PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE
- * PTRACE_GETVSRREGS returns VSR[0..31]
- *
- * PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need
- * to save FPSCR too.
- *
- * There 32 VSX double word registers to save since the 32 first VSX double
- * word registers are saved through FPR[0..32] and the remaining registers
- * are saved when saving the Altivec registers VR[0..32].
- */
-
-static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp)
-{
- if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) {
- pr_perror("Couldn't get floating-point registers");
- return -1;
- }
- fp->flags |= USER_FPREGS_FL_FP;
-
- return 0;
-}
-
static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe)
{
int i;
@@ -209,24 +151,6 @@ static UserPpc64VrstateEntry *copy_altivec_regs(__vector128 *vrregs)
return vse;
}
-static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp)
-{
- if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) {
- /* PTRACE_GETVRREGS returns EIO if Altivec is not supported.
- * This should not happen if msr_vec is set. */
- if (errno != EIO) {
- pr_perror("Couldn't get Altivec registers");
- return -1;
- }
- pr_debug("Altivec not supported\n");
- }
- else {
- pr_debug("Dumping Altivec registers\n");
- fp->flags |= USER_FPREGS_FL_ALTIVEC;
- }
- return 0;
-}
-
static int put_altivec_regs(mcontext_t *mc, UserPpc64VrstateEntry *vse)
{
vrregset_t *v_regs = (vrregset_t *)(((unsigned long)mc->vmx_reserve + 15) & ~0xful);
@@ -278,35 +202,6 @@ static UserPpc64VsxstateEntry* copy_vsx_regs(uint64_t *vsregs)
return vse;
}
-/*
- * Since the FPR[0-31] is stored in the first double word of VSR[0-31] and
- * FPR are saved through the FP state, there is no need to save the upper part
- * of the first 32 VSX registers.
- * Furthermore, the 32 last VSX registers are also the 32 Altivec registers
- * already saved, so no need to save them.
- * As a consequence, only the doubleword 1 of the 32 first VSX registers have
- * to be saved (the ones are returned by PTRACE_GETVSRREGS).
- */
-static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp)
-{
- if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) {
- /*
- * EIO is returned in the case PTRACE_GETVRREGS is not
- * supported.
- */
- if (errno != EIO) {
- pr_perror("Couldn't get VSX registers");
- return -1;
- }
- pr_debug("VSX register's dump not supported.\n");
- }
- else {
- pr_debug("Dumping VSX registers\n");
- fp->flags |= USER_FPREGS_FL_VSX;
- }
- return 0;
-}
-
static int put_vsx_regs(mcontext_t *mc, UserPpc64VsxstateEntry *vse)
{
uint64_t *buf;
@@ -415,56 +310,6 @@ static void xfree_tm_state(UserPpc64TmRegsEntry *tme)
}
}
-static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs)
-{
- struct iovec iov;
-
- pr_debug("Dumping TM registers\n");
-
-#define TM_REQUIRED 0
-#define TM_OPTIONAL 1
-#define PTRACE_GET_TM(s,n,c,u) do { \
- iov.iov_base = &s; \
- iov.iov_len = sizeof(s); \
- if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \
- if (!u || errno != EIO) { \
- pr_perror("Couldn't get TM "n); \
- pr_err("Your kernel seems to not support the " \
- "new TM ptrace API (>= 4.8)\n"); \
- goto out_free; \
- } \
- pr_debug("TM "n" not supported.\n"); \
- iov.iov_base = NULL; \
- } \
-} while(0)
-
- /* Get special registers */
- PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED);
-
- /* Get checkpointed regular registers */
- PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED);
-
- /* Get checkpointed FP registers */
- PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL);
- if (iov.iov_base)
- fpregs->tm.flags |= USER_FPREGS_FL_FP;
-
- /* Get checkpointed VMX (Altivec) registers */
- PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL);
- if (iov.iov_base)
- fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC;
-
- /* Get checkpointed VSX registers */
- PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL);
- if (iov.iov_base)
- fpregs->tm.flags |= USER_FPREGS_FL_VSX;
-
- return 0;
-
-out_free:
- return -1; /* still failing the checkpoint */
-}
-
static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme)
{
/*
@@ -499,71 +344,6 @@ static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme)
}
/****************************************************************************/
-static int __get_task_regs(pid_t pid, user_regs_struct_t *regs,
- user_fpregs_struct_t *fpregs)
-{
- pr_info("Dumping GP/FPU registers for %d\n", pid);
-
- /*
- * This is inspired by kernel function check_syscall_restart in
- * arch/powerpc/kernel/signal.c
- */
-#ifndef TRAP
-#define TRAP(r) ((r).trap & ~0xF)
-#endif
-
- if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) {
- /* Restart the system call */
- switch (regs->gpr[3]) {
- case ERESTARTNOHAND:
- case ERESTARTSYS:
- case ERESTARTNOINTR:
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4;
- break;
- case ERESTART_RESTARTBLOCK:
- regs->gpr[0] = __NR_restart_syscall;
- regs->nip -= 4;
- break;
- }
- }
-
- /* Resetting trap since we are now coming from user space. */
- regs->trap = 0;
-
- fpregs->flags = 0;
- /*
- * Check for Transactional Memory operation in progress.
- * Until we have support of TM register's state through the ptrace API,
- * we can't checkpoint process with TM operation in progress (almost
- * impossible) or suspended (easy to get).
- */
- if (MSR_TM_ACTIVE(regs->msr)) {
- pr_debug("Task %d has %s TM operation at 0x%lx\n",
- pid,
- (regs->msr & MSR_TMS) ? "a suspended" : "an active",
- regs->nip);
- if (get_tm_regs(pid, fpregs))
- return -1;
- fpregs->flags = USER_FPREGS_FL_TM;
- }
-
- if (get_fpu_regs(pid, fpregs))
- return -1;
-
- if (get_altivec_regs(pid, fpregs))
- return -1;
-
- if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) {
- /*
- * Save the VSX registers if Altivec registers are supported
- */
- if (get_vsx_regs(pid, fpregs))
- return -1;
- }
- return 0;
-}
-
static int copy_tm_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpregs,
CoreEntry *core)
{
@@ -701,18 +481,6 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
}
/****************************************************************************/
-int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
-{
- user_fpregs_struct_t fpregs;
- int ret;
-
- ret = __get_task_regs(pid, ®s, &fpregs);
- if (ret)
- return ret;
-
- return save(arg, ®s, &fpregs);
-}
-
int arch_alloc_thread_info(CoreEntry *core)
{
ThreadInfoPpc64 *ti_ppc64;
diff --git a/criu/arch/ppc64/include/asm/dump.h b/criu/arch/ppc64/include/asm/dump.h
index 0c88b7a56235..6439adafd8ca 100644
--- a/criu/arch/ppc64/include/asm/dump.h
+++ b/criu/arch/ppc64/include/asm/dump.h
@@ -1,9 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
-typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
-extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
diff --git a/criu/arch/ppc64/infect.c b/criu/arch/ppc64/infect.c
index c1c1174aaffa..6c9692f7c717 100644
--- a/criu/arch/ppc64/infect.c
+++ b/criu/arch/ppc64/infect.c
@@ -1,5 +1,243 @@
+#include <sys/ptrace.h>
#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
+#include "ptrace.h"
#include "parasite-syscall.h"
+#include "errno.h"
+#include "criu-log.h"
#include "infect.h"
#include "infect-priv.h"
+
+#ifndef NT_PPC_TM_SPR
+#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
+#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
+#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
+#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
+#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
+#endif
+
+/* This is the layout of the POWER7 VSX registers and the way they
+ * overlap with the existing FPR and VMX registers.
+ *
+ * VSR doubleword 0 VSR doubleword 1
+ * ----------------------------------------------------------------
+ * VSR[0] | FPR[0] | |
+ * ----------------------------------------------------------------
+ * VSR[1] | FPR[1] | |
+ * ----------------------------------------------------------------
+ * | ... | |
+ * ----------------------------------------------------------------
+ * VSR[30] | FPR[30] | |
+ * ----------------------------------------------------------------
+ * VSR[31] | FPR[31] | |
+ * ----------------------------------------------------------------
+ * VSR[32] | VR[0] |
+ * ----------------------------------------------------------------
+ * VSR[33] | VR[1] |
+ * ----------------------------------------------------------------
+ * | ... |
+ * ----------------------------------------------------------------
+ * VSR[62] | VR[30] |
+ * ----------------------------------------------------------------
+ * VSR[63] | VR[31] |
+ * ----------------------------------------------------------------
+ *
+ * PTRACE_GETFPREGS returns FPR[0..31] + FPSCR
+ * PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE
+ * PTRACE_GETVSRREGS returns VSR[0..31]
+ *
+ * PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need
+ * to save FPSCR too.
+ *
+ * There 32 VSX double word registers to save since the 32 first VSX double
+ * word registers are saved through FPR[0..32] and the remaining registers
+ * are saved when saving the Altivec registers VR[0..32].
+ */
+
+static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp)
+{
+ if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) {
+ pr_perror("Couldn't get floating-point registers");
+ return -1;
+ }
+ fp->flags |= USER_FPREGS_FL_FP;
+
+ return 0;
+}
+
+static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp)
+{
+ if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) {
+ /* PTRACE_GETVRREGS returns EIO if Altivec is not supported.
+ * This should not happen if msr_vec is set. */
+ if (errno != EIO) {
+ pr_perror("Couldn't get Altivec registers");
+ return -1;
+ }
+ pr_debug("Altivec not supported\n");
+ }
+ else {
+ pr_debug("Dumping Altivec registers\n");
+ fp->flags |= USER_FPREGS_FL_ALTIVEC;
+ }
+ return 0;
+}
+
+/*
+ * Since the FPR[0-31] is stored in the first double word of VSR[0-31] and
+ * FPR are saved through the FP state, there is no need to save the upper part
+ * of the first 32 VSX registers.
+ * Furthermore, the 32 last VSX registers are also the 32 Altivec registers
+ * already saved, so no need to save them.
+ * As a consequence, only the doubleword 1 of the 32 first VSX registers have
+ * to be saved (the ones are returned by PTRACE_GETVSRREGS).
+ */
+static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp)
+{
+ if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) {
+ /*
+ * EIO is returned in the case PTRACE_GETVRREGS is not
+ * supported.
+ */
+ if (errno != EIO) {
+ pr_perror("Couldn't get VSX registers");
+ return -1;
+ }
+ pr_debug("VSX register's dump not supported.\n");
+ }
+ else {
+ pr_debug("Dumping VSX registers\n");
+ fp->flags |= USER_FPREGS_FL_VSX;
+ }
+ return 0;
+}
+
+static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs)
+{
+ struct iovec iov;
+
+ pr_debug("Dumping TM registers\n");
+
+#define TM_REQUIRED 0
+#define TM_OPTIONAL 1
+#define PTRACE_GET_TM(s,n,c,u) do { \
+ iov.iov_base = &s; \
+ iov.iov_len = sizeof(s); \
+ if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \
+ if (!u || errno != EIO) { \
+ pr_perror("Couldn't get TM "n); \
+ pr_err("Your kernel seems to not support the " \
+ "new TM ptrace API (>= 4.8)\n"); \
+ goto out_free; \
+ } \
+ pr_debug("TM "n" not supported.\n"); \
+ iov.iov_base = NULL; \
+ } \
+} while(0)
+
+ /* Get special registers */
+ PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED);
+
+ /* Get checkpointed regular registers */
+ PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED);
+
+ /* Get checkpointed FP registers */
+ PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL);
+ if (iov.iov_base)
+ fpregs->tm.flags |= USER_FPREGS_FL_FP;
+
+ /* Get checkpointed VMX (Altivec) registers */
+ PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL);
+ if (iov.iov_base)
+ fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC;
+
+ /* Get checkpointed VSX registers */
+ PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL);
+ if (iov.iov_base)
+ fpregs->tm.flags |= USER_FPREGS_FL_VSX;
+
+ return 0;
+
+out_free:
+ return -1; /* still failing the checkpoint */
+}
+
+static int __get_task_regs(pid_t pid, user_regs_struct_t *regs,
+ user_fpregs_struct_t *fpregs)
+{
+ pr_info("Dumping GP/FPU registers for %d\n", pid);
+
+ /*
+ * This is inspired by kernel function check_syscall_restart in
+ * arch/powerpc/kernel/signal.c
+ */
+#ifndef TRAP
+#define TRAP(r) ((r).trap & ~0xF)
+#endif
+
+ if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) {
+ /* Restart the system call */
+ switch (regs->gpr[3]) {
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4;
+ break;
+ case ERESTART_RESTARTBLOCK:
+ regs->gpr[0] = __NR_restart_syscall;
+ regs->nip -= 4;
+ break;
+ }
+ }
+
+ /* Resetting trap since we are now coming from user space. */
+ regs->trap = 0;
+
+ fpregs->flags = 0;
+ /*
+ * Check for Transactional Memory operation in progress.
+ * Until we have support of TM register's state through the ptrace API,
+ * we can't checkpoint process with TM operation in progress (almost
+ * impossible) or suspended (easy to get).
+ */
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ pr_debug("Task %d has %s TM operation at 0x%lx\n",
+ pid,
+ (regs->msr & MSR_TMS) ? "a suspended" : "an active",
+ regs->nip);
+ if (get_tm_regs(pid, fpregs))
+ return -1;
+ fpregs->flags = USER_FPREGS_FL_TM;
+ }
+
+ if (get_fpu_regs(pid, fpregs))
+ return -1;
+
+ if (get_altivec_regs(pid, fpregs))
+ return -1;
+
+ if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) {
+ /*
+ * Save the VSX registers if Altivec registers are supported
+ */
+ if (get_vsx_regs(pid, fpregs))
+ return -1;
+ }
+ return 0;
+}
+
+int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
+{
+ user_fpregs_struct_t fpregs;
+ int ret;
+
+ ret = __get_task_regs(pid, ®s, &fpregs);
+ if (ret)
+ return ret;
+
+ return save(arg, ®s, &fpregs);
+}
diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c
index dbc04915fefd..363a52e07c88 100644
--- a/criu/arch/x86/crtools.c
+++ b/criu/arch/x86/crtools.c
@@ -187,73 +187,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
return err;
}
-#define get_signed_user_reg(pregs, name) \
- ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \
- (int32_t)((pregs)->compat.name))
-
-int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
-{
- user_fpregs_struct_t xsave = { }, *xs = NULL;
-
- struct iovec iov;
- int ret = -1;
-
- pr_info("Dumping general registers for %d in %s mode\n", pid,
- user_regs_native(®s) ? "native" : "compat");
-
- /* Did we come from a system call? */
- if (get_signed_user_reg(®s, orig_ax) >= 0) {
- /* Restart the system call */
- switch (get_signed_user_reg(®s, ax)) {
- case -ERESTARTNOHAND:
- case -ERESTARTSYS:
- case -ERESTARTNOINTR:
- set_user_reg(®s, ax, get_user_reg(®s, orig_ax));
- set_user_reg(®s, ip, get_user_reg(®s, ip) - 2);
- break;
- case -ERESTART_RESTARTBLOCK:
- pr_warn("Will restore %d with interrupted system call\n", pid);
- set_user_reg(®s, ax, -EINTR);
- break;
- }
- }
-
-#ifndef PTRACE_GETREGSET
-# define PTRACE_GETREGSET 0x4204
-#endif
-
- if (!cpu_has_feature(X86_FEATURE_FPU))
- goto out;
-
- /*
- * FPU fetched either via fxsave or via xsave,
- * thus decode it accrodingly.
- */
-
- pr_info("Dumping GP/FPU registers for %d\n", pid);
-
- if (cpu_has_feature(X86_FEATURE_XSAVE)) {
- iov.iov_base = &xsave;
- iov.iov_len = sizeof(xsave);
-
- if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) {
- pr_perror("Can't obtain FPU registers for %d", pid);
- goto err;
- }
- } else {
- if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) {
- pr_perror("Can't obtain FPU registers for %d", pid);
- goto err;
- }
- }
-
- xs = &xsave;
-out:
- ret = save(arg, ®s, xs);
-err:
- return ret;
-}
-
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;
diff --git a/criu/arch/x86/include/asm/dump.h b/criu/arch/x86/include/asm/dump.h
index 4b928a8de662..61e53dced564 100644
--- a/criu/arch/x86/include/asm/dump.h
+++ b/criu/arch/x86/include/asm/dump.h
@@ -1,9 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
-typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
-extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c
index c1c1174aaffa..7c7537cb26d3 100644
--- a/criu/arch/x86/infect.c
+++ b/criu/arch/x86/infect.c
@@ -1,5 +1,78 @@
+#include <sys/ptrace.h>
#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/auxv.h>
+#include "asm/fpu.h"
#include "asm/types.h"
+#include "errno.h"
+#include "asm/cpu.h"
#include "parasite-syscall.h"
#include "infect.h"
#include "infect-priv.h"
+
+#define get_signed_user_reg(pregs, name) \
+ ((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \
+ (int32_t)((pregs)->compat.name))
+
+int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
+{
+ user_fpregs_struct_t xsave = { }, *xs = NULL;
+
+ struct iovec iov;
+ int ret = -1;
+
+ pr_info("Dumping general registers for %d in %s mode\n", pid,
+ user_regs_native(®s) ? "native" : "compat");
+
+ /* Did we come from a system call? */
+ if (get_signed_user_reg(®s, orig_ax) >= 0) {
+ /* Restart the system call */
+ switch (get_signed_user_reg(®s, ax)) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ set_user_reg(®s, ax, get_user_reg(®s, orig_ax));
+ set_user_reg(®s, ip, get_user_reg(®s, ip) - 2);
+ break;
+ case -ERESTART_RESTARTBLOCK:
+ pr_warn("Will restore %d with interrupted system call\n", pid);
+ set_user_reg(®s, ax, -EINTR);
+ break;
+ }
+ }
+
+#ifndef PTRACE_GETREGSET
+# define PTRACE_GETREGSET 0x4204
+#endif
+
+ if (!cpu_has_feature(X86_FEATURE_FPU))
+ goto out;
+
+ /*
+ * FPU fetched either via fxsave or via xsave,
+ * thus decode it accrodingly.
+ */
+
+ pr_info("Dumping GP/FPU registers for %d\n", pid);
+
+ if (cpu_has_feature(X86_FEATURE_XSAVE)) {
+ iov.iov_base = &xsave;
+ iov.iov_len = sizeof(xsave);
+
+ if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) {
+ pr_perror("Can't obtain FPU registers for %d", pid);
+ goto err;
+ }
+ } else {
+ if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) {
+ pr_perror("Can't obtain FPU registers for %d", pid);
+ goto err;
+ }
+ }
+
+ xs = &xsave;
+out:
+ ret = save(arg, ®s, xs);
+err:
+ return ret;
+}
diff --git a/criu/include/infect.h b/criu/include/infect.h
index 072143eedcf3..40ec9132d19c 100644
--- a/criu/include/infect.h
+++ b/criu/include/infect.h
@@ -105,4 +105,7 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *);
#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */
#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */
+typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
+extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
+
#endif
diff --git a/criu/infect.c b/criu/infect.c
index 008c253a2ef1..5090413b1b6e 100644
--- a/criu/infect.c
+++ b/criu/infect.c
@@ -581,11 +581,11 @@ static int parasite_start_daemon(struct parasite_ctl *ctl)
/*
* Get task registers before going daemon, since the
- * get_task_regs needs to call ptrace on _stopped_ task,
+ * compel_get_task_regs needs to call ptrace on _stopped_ task,
* while in daemon it is not such.
*/
- if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
+ if (compel_get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
pr_err("Can't obtain regs for thread %d\n", pid);
return -1;
}
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index 6f4b54ab6005..5d918c95901a 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -243,7 +243,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
return -1;
}
- ret = get_task_regs(pid, octx.regs, save_task_regs, core);
+ ret = compel_get_task_regs(pid, octx.regs, save_task_regs, core);
if (ret) {
pr_err("Can't obtain regs for thread %d\n", pid);
return -1;
--
2.7.4
More information about the CRIU
mailing list