[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 = &regs;
-	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, &regs, &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 = &regs;
+	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, &regs, &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, &regs, &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, &regs, &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, &regs, &fpregs);
-	if (ret)
-		return ret;
-
-	return save(arg, &regs, &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, &regs, &fpregs);
+	if (ret)
+		return ret;
+
+	return save(arg, &regs, &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(&regs) ? "native" : "compat");
-
-	/* Did we come from a system call? */
-	if (get_signed_user_reg(&regs, orig_ax) >= 0) {
-		/* Restart the system call */
-		switch (get_signed_user_reg(&regs, ax)) {
-		case -ERESTARTNOHAND:
-		case -ERESTARTSYS:
-		case -ERESTARTNOINTR:
-			set_user_reg(&regs, ax, get_user_reg(&regs, orig_ax));
-			set_user_reg(&regs, ip, get_user_reg(&regs, ip) - 2);
-			break;
-		case -ERESTART_RESTARTBLOCK:
-			pr_warn("Will restore %d with interrupted system call\n", pid);
-			set_user_reg(&regs, 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, &regs, 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(&regs) ? "native" : "compat");
+
+	/* Did we come from a system call? */
+	if (get_signed_user_reg(&regs, orig_ax) >= 0) {
+		/* Restart the system call */
+		switch (get_signed_user_reg(&regs, ax)) {
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
+			set_user_reg(&regs, ax, get_user_reg(&regs, orig_ax));
+			set_user_reg(&regs, ip, get_user_reg(&regs, ip) - 2);
+			break;
+		case -ERESTART_RESTARTBLOCK:
+			pr_warn("Will restore %d with interrupted system call\n", pid);
+			set_user_reg(&regs, 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, &regs, 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