[CRIU] [PATCH 2/3] cr: implemented the support for the AArch64 architecture

Alexander Kartashov alekskartashov at parallels.com
Wed Apr 9 22:30:47 PDT 2014


aarch64: TLS register checkpoint/restore implementation by Christopher Covington.

Signed-off-by: Alexander Kartashov <alekskartashov at parallels.com>
Signed-off-by: Christopher Covington <cov at codeaurora.org>
Reviewed-by: Christopher Covington <cov at codeaurora.org>
---
 arch/aarch64/Makefile                       |   59 +++++++
 arch/aarch64/cpu.c                          |   18 ++
 arch/aarch64/crtools.c                      |  235 +++++++++++++++++++++++++++
 arch/aarch64/include/asm/atomic.h           |   76 +++++++++
 arch/aarch64/include/asm/bitops.h           |    7 +
 arch/aarch64/include/asm/bitsperlong.h      |    6 +
 arch/aarch64/include/asm/cpu.h              |    1 +
 arch/aarch64/include/asm/dump.h             |   14 ++
 arch/aarch64/include/asm/fpu.h              |    4 +
 arch/aarch64/include/asm/int.h              |    6 +
 arch/aarch64/include/asm/linkage.h          |   24 +++
 arch/aarch64/include/asm/parasite-syscall.h |   18 ++
 arch/aarch64/include/asm/parasite.h         |   11 ++
 arch/aarch64/include/asm/processor-flags.h  |    4 +
 arch/aarch64/include/asm/restore.h          |   28 ++++
 arch/aarch64/include/asm/restorer.h         |  111 +++++++++++++
 arch/aarch64/include/asm/string.h           |    7 +
 arch/aarch64/include/asm/syscall-aux.S      |   37 +++++
 arch/aarch64/include/asm/syscall-aux.h      |    1 +
 arch/aarch64/include/asm/types.h            |   87 ++++++++++
 arch/aarch64/include/asm/vdso.h             |   47 ++++++
 arch/aarch64/parasite-head.S                |   21 +++
 arch/aarch64/restorer.c                     |   15 ++
 arch/aarch64/syscall-common.S               |   19 +++
 arch/aarch64/vdso-pie.c                     |   34 ++++
 arch/aarch64/vdso.c                         |   36 ++++
 26 files changed, 926 insertions(+)
 create mode 100644 arch/aarch64/Makefile
 create mode 100644 arch/aarch64/cpu.c
 create mode 100644 arch/aarch64/crtools.c
 create mode 100644 arch/aarch64/include/asm/atomic.h
 create mode 100644 arch/aarch64/include/asm/bitops.h
 create mode 100644 arch/aarch64/include/asm/bitsperlong.h
 create mode 100644 arch/aarch64/include/asm/cpu.h
 create mode 100644 arch/aarch64/include/asm/dump.h
 create mode 100644 arch/aarch64/include/asm/fpu.h
 create mode 100644 arch/aarch64/include/asm/int.h
 create mode 100644 arch/aarch64/include/asm/linkage.h
 create mode 100644 arch/aarch64/include/asm/parasite-syscall.h
 create mode 100644 arch/aarch64/include/asm/parasite.h
 create mode 100644 arch/aarch64/include/asm/processor-flags.h
 create mode 100644 arch/aarch64/include/asm/restore.h
 create mode 100644 arch/aarch64/include/asm/restorer.h
 create mode 100644 arch/aarch64/include/asm/string.h
 create mode 100644 arch/aarch64/include/asm/syscall-aux.S
 create mode 100644 arch/aarch64/include/asm/syscall-aux.h
 create mode 100644 arch/aarch64/include/asm/types.h
 create mode 100644 arch/aarch64/include/asm/vdso.h
 create mode 100644 arch/aarch64/parasite-head.S
 create mode 100644 arch/aarch64/restorer.c
 create mode 100644 arch/aarch64/syscall-common.S
 create mode 100644 arch/aarch64/vdso-pie.c
 create mode 100644 arch/aarch64/vdso.c

diff --git a/arch/aarch64/Makefile b/arch/aarch64/Makefile
new file mode 100644
index 0000000..200d37c
--- /dev/null
+++ b/arch/aarch64/Makefile
@@ -0,0 +1,59 @@
+targets		+= syscalls
+targets		+= crtools
+
+SYS-ASM		:= syscalls.S
+
+syscalls-asm-y	+= $(SYS-ASM:.S=).o
+crtools-obj-y	+= crtools.o
+crtools-obj-y	+= cpu.o
+
+SYS-DEF		:= ../arm/syscall.def
+SYS-ASM-COMMON	:= syscall-common.S
+SYS-TYPES	:= include/syscall-types.h
+
+SYS-CODES	:= include/syscall-codes.h
+SYS-PROTO	:= include/syscall.h
+
+SYS-GEN		:= ../scripts/arm/gen-syscalls.pl
+SYS-GEN-TBL	:= ../scripts/arm/gen-sys-exec-tbl.pl
+
+SYS-EXEC-TBL	:= sys-exec-tbl.c
+
+syscalls-asm-y-asmflags		+= -fpie -Wstrict-prototypes -Wa,--noexecstack
+syscalls-asm-y-asmflags		+= -nostdlib -fomit-frame-pointer -I$(obj)
+ASMFLAGS	+= -D__ASSEMBLY__
+
+ARCH_BITS	:= 64
+
+$(obj)/$(SYS-ASM): $(obj)/$(SYS-GEN) $(obj)/$(SYS-DEF) $(obj)/$(SYS-ASM-COMMON) $(SYS-TYPES)
+	$(E) "  GEN     " $@
+	$(Q) perl			\
+		$(obj)/$(SYS-GEN)	\
+		$(obj)/$(SYS-DEF)	\
+		$(SYS-CODES)		\
+		$(SYS-PROTO)		\
+		$(obj)/$(SYS-ASM)	\
+		$(SYS-ASM-COMMON)	\
+		$(SYS-TYPES)		\
+		$(ARCH_BITS)
+
+$(obj)/syscalls.o: $(obj)/$(SYS-ASM)
+
+$(obj)/$(SYS-EXEC-TBL): $(obj)/$(SYS-GEN-TBL) $(obj)/$(SYS-DEF)
+	$(E) "  GEN     " $@
+	$(Q) perl			\
+		$(obj)/$(SYS-GEN-TBL)	\
+		$(obj)/$(SYS-DEF)	\
+		$(obj)/$(SYS-EXEC-TBL)	\
+		$(ARCH_BITS)
+
+_all += $(obj)/$(SYS-EXEC-TBL)
+
+cleanup-y += $(obj)/$(SYS-EXEC-TBL) $(obj)/$(SYS-ASM)
+cleanup-y += $(SYS-CODES)
+cleanup-y += $(SYS-PROTO)
+
+ifneq ($(MAKECMDGOALS),clean)
+deps-after := $(obj)/$(SYS-ASM)
+incdeps := y
+endif
diff --git a/arch/aarch64/cpu.c b/arch/aarch64/cpu.c
new file mode 100644
index 0000000..6f4b528
--- /dev/null
+++ b/arch/aarch64/cpu.c
@@ -0,0 +1,18 @@
+#undef	LOG_PREFIX
+#define LOG_PREFIX "cpu: "
+
+#include "cpu.h"
+
+void cpu_set_feature(unsigned int feature)
+{
+}
+
+bool cpu_has_feature(unsigned int feature)
+{
+	return false;
+}
+
+int cpu_init(void)
+{
+	return 0;
+}
diff --git a/arch/aarch64/crtools.c b/arch/aarch64/crtools.c
new file mode 100644
index 0000000..18224b0
--- /dev/null
+++ b/arch/aarch64/crtools.c
@@ -0,0 +1,235 @@
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/elf.h>
+
+#include "asm/types.h"
+#include "asm/restorer.h"
+#include "compiler.h"
+#include "ptrace.h"
+#include "asm/processor-flags.h"
+#include "protobuf.h"
+#include "protobuf/core.pb-c.h"
+#include "protobuf/creds.pb-c.h"
+#include "parasite-syscall.h"
+#include "syscall.h"
+#include "log.h"
+#include "util.h"
+#include "cpu.h"
+#include "parasite-syscall.h"
+#include "restorer.h"
+
+
+/*
+ * Injected syscall instruction
+ */
+const char code_syscall[] = {
+	0x01, 0x00, 0x00, 0xd4,		/* SVC #0 */
+	0x00, 0x00, 0x20, 0xd4		/* BRK #0 */
+};
+
+const int code_syscall_size = round_up(sizeof(code_syscall), sizeof(long));
+
+static inline void __check_code_syscall(void)
+{
+	BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE);
+	BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
+}
+
+
+void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs)
+{
+	regs->pc = new_ip;
+	if (stack)
+		regs->sp = (unsigned long)stack;
+}
+
+bool arch_can_dump_task(pid_t pid)
+{
+	/*
+	 * TODO: Add proper check here
+	 */
+	return true;
+}
+
+int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
+					unsigned long arg1,
+					unsigned long arg2,
+					unsigned long arg3,
+					unsigned long arg4,
+					unsigned long arg5,
+					unsigned long arg6)
+{
+	user_regs_struct_t regs = ctl->orig.regs;
+	int err;
+
+	regs.regs[8] = (unsigned long)nr;
+	regs.regs[0] = arg1;
+	regs.regs[1] = arg2;
+	regs.regs[2] = arg3;
+	regs.regs[3] = arg4;
+	regs.regs[4] = arg5;
+	regs.regs[5] = arg6;
+	regs.regs[6] = 0;
+	regs.regs[7] = 0;
+
+	err = __parasite_execute_syscall(ctl, &regs);
+
+	*ret = regs.regs[0];
+	return err;
+}
+
+
+#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, CoreEntry *core)
+{
+	struct iovec iov;
+	struct user_fpsimd_state fpsimd;
+	int i, 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_err("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_err("Failed to obtain FPU registers for %d!", pid);
+		goto err;
+	}
+
+
+	// Save the Aarch64 CPU state
+	for (i = 0; i < 31; ++i)
+		assign_reg(core->ti_aarch64->gpregs, regs, regs[i]);
+	assign_reg(core->ti_aarch64->gpregs, regs, sp);
+	assign_reg(core->ti_aarch64->gpregs, regs, pc);
+	assign_reg(core->ti_aarch64->gpregs, regs, pstate);
+
+
+	// Save the FP/SIMD state
+	for (i = 0; i < 32; ++i)
+	{
+		core->ti_aarch64->fpsimd->vregs[2*i]     = fpsimd.vregs[i];
+		core->ti_aarch64->fpsimd->vregs[2*i + 1] = fpsimd.vregs[i] >> 64;
+	}
+	assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpsr);
+	assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpcr);
+
+	ret = 0;
+
+err:
+	return ret;
+}
+
+int arch_alloc_thread_info(CoreEntry *core)
+{
+	ThreadInfoAarch64 *ti_aarch64;
+	UserAarch64RegsEntry *gpregs;
+	UserAarch64FpsimdContextEntry *fpsimd;
+
+	ti_aarch64 = xmalloc(sizeof(*ti_aarch64));
+	if (!ti_aarch64)
+		goto err;
+	thread_info_aarch64__init(ti_aarch64);
+	core->ti_aarch64 = ti_aarch64;
+
+	gpregs = xmalloc(sizeof(*gpregs));
+	if (!gpregs)
+		goto err;
+	user_aarch64_regs_entry__init(gpregs);
+
+	gpregs->regs = xmalloc(31*sizeof(uint64_t));
+	if (!gpregs->regs)
+		goto err;
+	gpregs->n_regs = 31;
+
+	ti_aarch64->gpregs = gpregs;
+
+	fpsimd = xmalloc(sizeof(*fpsimd));
+	if (!fpsimd)
+		goto err;
+	user_aarch64_fpsimd_context_entry__init(fpsimd);
+	ti_aarch64->fpsimd = fpsimd;
+	fpsimd->vregs = xmalloc(64*sizeof(fpsimd->vregs[0]));
+	fpsimd->n_vregs = 64;
+	if (!fpsimd->vregs)
+		goto err;
+
+	return 0;
+err:
+	return -1;
+}
+
+void arch_free_thread_info(CoreEntry *core)
+{
+	if (CORE_THREAD_ARCH_INFO(core)) {
+		if (CORE_THREAD_ARCH_INFO(core)->fpsimd) {
+			xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd->vregs);
+			xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd);
+		}
+		xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->regs);
+		xfree(CORE_THREAD_ARCH_INFO(core)->gpregs);
+		xfree(CORE_THREAD_ARCH_INFO(core));
+		CORE_THREAD_ARCH_INFO(core) = NULL;
+	}
+}
+
+int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
+{
+	int i;
+	struct fpsimd_context *fpsimd = &RT_SIGFRAME_FPU(sigframe);
+
+	if (core->ti_aarch64->fpsimd->n_vregs != 64)
+		return 1;
+
+	for (i = 0; i < 32; ++i)
+		fpsimd->vregs[i] =	(__uint128_t)core->ti_aarch64->fpsimd->vregs[2*i] |
+					((__uint128_t)core->ti_aarch64->fpsimd->vregs[2*i + 1] << 64);
+	assign_reg(fpsimd, *core->ti_aarch64->fpsimd, fpsr);
+	assign_reg(fpsimd, *core->ti_aarch64->fpsimd, fpcr);
+
+	fpsimd->head.magic = FPSIMD_MAGIC;
+	fpsimd->head.size = sizeof(*fpsimd);
+
+	return 0;
+}
+
+void *mmap_seized(
+		struct parasite_ctl *ctl,
+		void *addr, size_t length, int prot,
+		int flags, int fd, off_t offset)
+{
+	unsigned long map;
+	int err;
+
+	err = syscall_seized(ctl, __NR_mmap, &map,
+			(unsigned long)addr, length, prot, flags, fd, offset);
+	if (err < 0 || map > TASK_SIZE)
+		map = 0;
+
+	return (void *)map;
+}
+
+int restore_gpregs(struct rt_sigframe *f, UserRegsEntry *r)
+{
+#define CPREG1(d)       f->uc.uc_mcontext.d = r->d
+
+	int i;
+
+	for (i = 0; i < 31; ++i)
+		CPREG1(regs[i]);
+	CPREG1(sp);
+	CPREG1(pc);
+	CPREG1(pstate);
+
+#undef CPREG1
+
+	return 0;
+}
diff --git a/arch/aarch64/include/asm/atomic.h b/arch/aarch64/include/asm/atomic.h
new file mode 100644
index 0000000..af13342
--- /dev/null
+++ b/arch/aarch64/include/asm/atomic.h
@@ -0,0 +1,76 @@
+#ifndef __CR_ATOMIC_H__
+#define __CR_ATOMIC_H__
+
+typedef struct {
+	int counter;
+} atomic_t;
+
+
+/* Copied from the Linux header arch/arm/include/asm/barrier.h */
+
+#define smp_mb()	asm volatile("dmb ish" : : : "memory")
+
+
+/* Copied from the Linux kernel header arch/arm64/include/asm/atomic.h */
+
+static inline int atomic_read(const atomic_t *v)
+{
+	return (*(volatile int *)&(v)->counter);
+}
+
+static inline void atomic_set(atomic_t *v, int i)
+{
+	v->counter = i;
+}
+
+#define atomic_get atomic_read
+
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile(
+"1:	ldxr	%w0, %2\n"
+"	add	%w0, %w0, %w3\n"
+"	stlxr	%w1, %w0, %2\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+	: "Ir" (i)
+	: "cc", "memory");
+
+	smp_mb();
+	return result;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	asm volatile(
+"1:	ldxr	%w0, %2\n"
+"	sub	%w0, %w0, %w3\n"
+"	stlxr	%w1, %w0, %2\n"
+"	cbnz	%w1, 1b"
+	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+	: "Ir" (i)
+	: "cc", "memory");
+
+	smp_mb();
+	return result;
+}
+
+static inline int atomic_inc(atomic_t *v) { return atomic_add_return(1, v) - 1; }
+
+static inline int atomic_add(int val, atomic_t *v) { return atomic_add_return(val, v) - val; }
+
+static inline int atomic_dec(atomic_t *v) { return atomic_sub_return(1, v) + 1; }
+
+/* true if the result is 0, or false for all other cases. */
+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+
+#define atomic_inc_return(v)	(atomic_add_return(1, v))
+
+#endif /* __CR_ATOMIC_H__ */
diff --git a/arch/aarch64/include/asm/bitops.h b/arch/aarch64/include/asm/bitops.h
new file mode 100644
index 0000000..5a75044
--- /dev/null
+++ b/arch/aarch64/include/asm/bitops.h
@@ -0,0 +1,7 @@
+#ifndef __CR_ASM_BITOPS_H__
+#define __CR_ASM_BITOPS_H__
+
+#include "compiler.h"
+#include "asm-generic/bitops.h"
+
+#endif /* __CR_ASM_BITOPS_H__ */
diff --git a/arch/aarch64/include/asm/bitsperlong.h b/arch/aarch64/include/asm/bitsperlong.h
new file mode 100644
index 0000000..d95727d
--- /dev/null
+++ b/arch/aarch64/include/asm/bitsperlong.h
@@ -0,0 +1,6 @@
+#ifndef __CR_BITSPERLONG_H__
+#define __CR_BITSPERLONG_H__
+
+#define BITS_PER_LONG 64
+
+#endif /* __CR_BITSPERLONG_H__ */
diff --git a/arch/aarch64/include/asm/cpu.h b/arch/aarch64/include/asm/cpu.h
new file mode 100644
index 0000000..59118c2
--- /dev/null
+++ b/arch/aarch64/include/asm/cpu.h
@@ -0,0 +1 @@
+#include <stdbool.h>
diff --git a/arch/aarch64/include/asm/dump.h b/arch/aarch64/include/asm/dump.h
new file mode 100644
index 0000000..671c424
--- /dev/null
+++ b/arch/aarch64/include/asm/dump.h
@@ -0,0 +1,14 @@
+#ifndef __CR_ASM_DUMP_H__
+#define __CR_ASM_DUMP_H__
+
+extern int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core);
+extern int arch_alloc_thread_info(CoreEntry *core);
+extern void arch_free_thread_info(CoreEntry *core);
+
+
+static inline void core_put_tls(CoreEntry *core, tls_t tls)
+{
+	core->ti_aarch64->tls = tls;
+}
+
+#endif
diff --git a/arch/aarch64/include/asm/fpu.h b/arch/aarch64/include/asm/fpu.h
new file mode 100644
index 0000000..7f476d5
--- /dev/null
+++ b/arch/aarch64/include/asm/fpu.h
@@ -0,0 +1,4 @@
+#ifndef __CR_ASM_FPU_H__
+#define __CR_ASM_FPU_H__
+
+#endif /* __CR_ASM_FPU_H__ */
diff --git a/arch/aarch64/include/asm/int.h b/arch/aarch64/include/asm/int.h
new file mode 100644
index 0000000..642804e
--- /dev/null
+++ b/arch/aarch64/include/asm/int.h
@@ -0,0 +1,6 @@
+#ifndef __CR_ASM_INT_H__
+#define __CR_ASM_INT_H__
+
+#include "asm-generic/int.h"
+
+#endif /* __CR_ASM_INT_H__ */
diff --git a/arch/aarch64/include/asm/linkage.h b/arch/aarch64/include/asm/linkage.h
new file mode 100644
index 0000000..7380642
--- /dev/null
+++ b/arch/aarch64/include/asm/linkage.h
@@ -0,0 +1,24 @@
+#ifndef __CR_LINKAGE_H__
+#define __CR_LINKAGE_H__
+
+#ifdef __ASSEMBLY__
+
+#define __ALIGN		.align 4, 0x00
+#define __ALIGN_STR	".align 4, 0x00"
+
+#define GLOBAL(name)		\
+	.globl name;		\
+	name:
+
+#define ENTRY(name)		\
+	.globl name;		\
+	.type name, #function;	\
+	__ALIGN;		\
+	name:
+
+#define END(sym)		\
+	.size sym, . - sym
+
+#endif  /* __ASSEMBLY__ */
+
+#endif /* __CR_LINKAGE_H__ */
diff --git a/arch/aarch64/include/asm/parasite-syscall.h b/arch/aarch64/include/asm/parasite-syscall.h
new file mode 100644
index 0000000..0c66bf9
--- /dev/null
+++ b/arch/aarch64/include/asm/parasite-syscall.h
@@ -0,0 +1,18 @@
+#ifndef __CR_ASM_PARASITE_SYSCALL_H__
+#define __CR_ASM_PARASITE_SYSCALL_H__
+
+
+#define ARCH_SI_TRAP TRAP_BRKPT
+
+
+extern const char code_syscall[];
+extern const int code_syscall_size;
+
+
+void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs);
+
+void *mmap_seized(struct parasite_ctl *ctl,
+		  void *addr, size_t length, int prot,
+		  int flags, int fd, off_t offset);
+
+#endif
diff --git a/arch/aarch64/include/asm/parasite.h b/arch/aarch64/include/asm/parasite.h
new file mode 100644
index 0000000..2a1e1c1
--- /dev/null
+++ b/arch/aarch64/include/asm/parasite.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_PARASITE_H__
+#define __ASM_PARASITE_H__
+
+static inline void arch_get_tls(tls_t *ptls)
+{
+	tls_t tls;
+	asm("mrs %0, tpidr_el0" : "=r" (tls));
+	*ptls = tls;
+}
+
+#endif
diff --git a/arch/aarch64/include/asm/processor-flags.h b/arch/aarch64/include/asm/processor-flags.h
new file mode 100644
index 0000000..c1888af
--- /dev/null
+++ b/arch/aarch64/include/asm/processor-flags.h
@@ -0,0 +1,4 @@
+#ifndef __CR_PROCESSOR_FLAGS_H__
+#define __CR_PROCESSOR_FLAGS_H__
+
+#endif
diff --git a/arch/aarch64/include/asm/restore.h b/arch/aarch64/include/asm/restore.h
new file mode 100644
index 0000000..69404b0
--- /dev/null
+++ b/arch/aarch64/include/asm/restore.h
@@ -0,0 +1,28 @@
+#ifndef __CR_ASM_RESTORE_H__
+#define __CR_ASM_RESTORE_H__
+
+#include "asm/restorer.h"
+
+#include "protobuf/core.pb-c.h"
+
+#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start,	\
+			      task_args)			\
+	asm volatile(						\
+			"and  sp, %0, #~15		\n"	\
+			"mov  x0, %2			\n"	\
+			"br   %1			\n"	\
+			:					\
+			: "r"(new_sp),				\
+			  "r"(restore_task_exec_start),		\
+			  "r"(task_args)			\
+			: "sp", "x0", "memory")
+
+static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls)
+{
+	*ptls = pcore->ti_aarch64->tls;
+}
+
+
+int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
+
+#endif
diff --git a/arch/aarch64/include/asm/restorer.h b/arch/aarch64/include/asm/restorer.h
new file mode 100644
index 0000000..f4d45e6
--- /dev/null
+++ b/arch/aarch64/include/asm/restorer.h
@@ -0,0 +1,111 @@
+#ifndef __CR_ASM_RESTORER_H__
+#define __CR_ASM_RESTORER_H__
+
+#include <asm/sigcontext.h>
+#include <sys/ucontext.h>
+
+#include "asm/types.h"
+#include "protobuf/core.pb-c.h"
+
+/* Copied from the kernel header arch/arm64/include/uapi/asm/sigcontext.h */
+
+#define FPSIMD_MAGIC    0x46508001
+
+typedef struct fpsimd_context fpu_state_t;
+
+
+struct aux_context {
+	struct fpsimd_context fpsimd;
+	/* additional context to be added before "end" */
+	struct _aarch64_ctx end;
+};
+
+
+// XXX: the idetifier rt_sigcontext is expected to be struct by the CRIU code
+#define rt_sigcontext sigcontext
+
+
+#include "sigframe.h"
+
+
+/* Copied from the kernel source arch/arm64/kernel/signal.c */
+
+struct rt_sigframe {
+	siginfo_t info;
+	struct ucontext uc;
+	u64 fp;
+	u64 lr;
+};
+
+
+#define ARCH_RT_SIGRETURN(new_sp)						\
+	asm volatile(								\
+			"mov sp, %0					\n"	\
+			"mov x8, #"__stringify(__NR_rt_sigreturn)"	\n"	\
+			"svc #0						\n"	\
+			:							\
+			: "r"(new_sp)						\
+			: "sp", "x8", "memory")
+
+#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid,		\
+			     thread_args, clone_restore_fn)			\
+	asm volatile(								\
+			"clone_emul:					\n"	\
+			"and x1, %2, #~15				\n"	\
+			"sub x1, x2, #16				\n"	\
+			"stp %5, %6, [x1]				\n"	\
+			"mov x0, %1					\n"	\
+			"mov x2, %3					\n"	\
+			"mov x3, %4					\n"	\
+			"mov x8, #"__stringify(__NR_clone)"		\n"	\
+			"svc #0						\n"	\
+										\
+			"cbz x0, thread_run				\n"	\
+										\
+			"mov %0, x0					\n"	\
+			"b   clone_end					\n"	\
+										\
+			"thread_run:					\n"	\
+			"ldp x1, x0, [sp]				\n"	\
+			"br  x1						\n"	\
+										\
+			"clone_end:					\n"	\
+			: "=r"(ret)						\
+			: "r"(clone_flags),					\
+			  "r"(new_sp),						\
+			  "r"(&parent_tid),					\
+			  "r"(&thread_args[i].pid),				\
+			  "r"(clone_restore_fn),				\
+			  "r"(&thread_args[i])					\
+			: "x0", "x1", "x2", "x3", "x8", "memory")
+
+
+#define ARCH_FAIL_CORE_RESTORE					\
+	asm volatile(						\
+			"mov sp, %0			\n"	\
+			"mov x0, #0			\n"	\
+			"b   x0				\n"	\
+			:					\
+			: "r"(ret)				\
+			: "sp", "x0", "memory")
+
+
+#define RT_SIGFRAME_UC(rt_sigframe) rt_sigframe->uc
+#define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)(rt_sigframe)->uc.uc_mcontext.pc)
+#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1)
+#define RT_SIGFRAME_FPU(rt_sigframe) ((struct aux_context*)&(rt_sigframe)->uc.uc_mcontext.__reserved)->fpsimd
+
+#define SIGFRAME_OFFSET 0
+
+
+int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r);
+int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r);
+
+static inline int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, fpu_state_t *fpu_state) { return 0; }
+
+static inline void restore_tls(tls_t *ptls)
+{
+	asm("msr tpidr_el0, %0" : : "r" (*ptls));
+}
+
+#endif
diff --git a/arch/aarch64/include/asm/string.h b/arch/aarch64/include/asm/string.h
new file mode 100644
index 0000000..2c3a34f
--- /dev/null
+++ b/arch/aarch64/include/asm/string.h
@@ -0,0 +1,7 @@
+#ifndef __CR_ASM_STRING_H__
+#define __CR_ASM_STRING_H__
+
+#include "compiler.h"
+#include "asm-generic/string.h"
+
+#endif /* __CR_ASM_STRING_H__ */
diff --git a/arch/aarch64/include/asm/syscall-aux.S b/arch/aarch64/include/asm/syscall-aux.S
new file mode 100644
index 0000000..00ccf79
--- /dev/null
+++ b/arch/aarch64/include/asm/syscall-aux.S
@@ -0,0 +1,37 @@
+/**
+ * This source contains emulation of syscalls
+ * that are not implemented in the AArch64 Linux kernel
+ */
+
+ENTRY(sys_open)
+	mov x3, x2
+	mov x2, x1
+	mov x1, x0
+	mov x0, #-100
+	b   sys_openat
+END(sys_open)
+
+
+ENTRY(sys_mkdir)
+	mov x3, x2
+	mov x2, x1
+	mov x1, x0
+	mov x0, #-100
+	b   sys_mkdirat
+END(sys_mkdir)
+
+
+ENTRY(sys_rmdir)
+	mov x2, #0x200		// flags = AT_REMOVEDIR
+	mov x1, x0
+	mov x0, #-100
+	b   sys_unlinkat
+END(sys_rmdir)
+
+
+ENTRY(sys_unlink)
+	mov x2, #0		// flags = 0
+	mov x1, x0
+	mov x0, #-100
+	b   sys_unlinkat
+END(sys_unlink)
diff --git a/arch/aarch64/include/asm/syscall-aux.h b/arch/aarch64/include/asm/syscall-aux.h
new file mode 100644
index 0000000..814c7a9
--- /dev/null
+++ b/arch/aarch64/include/asm/syscall-aux.h
@@ -0,0 +1 @@
+#define __NR_openat 56
diff --git a/arch/aarch64/include/asm/types.h b/arch/aarch64/include/asm/types.h
new file mode 100644
index 0000000..73d0fec
--- /dev/null
+++ b/arch/aarch64/include/asm/types.h
@@ -0,0 +1,87 @@
+#ifndef __CR_ASM_TYPES_H__
+#define __CR_ASM_TYPES_H__
+
+#include <stdbool.h>
+#include <signal.h>
+#include "protobuf/core.pb-c.h"
+
+#include "asm-generic/page.h"
+#include "asm/bitops.h"
+#include "asm/int.h"
+
+
+#define SIGMAX			64
+#define SIGMAX_OLD		31
+
+#define MAJOR(dev)		((dev)>>8)
+#define MINOR(dev)		((dev) & 0xff)
+
+typedef void rt_signalfn_t(int, siginfo_t *, void *);
+typedef rt_signalfn_t *rt_sighandler_t;
+
+typedef void rt_restorefn_t(void);
+typedef rt_restorefn_t *rt_sigrestore_t;
+
+#define _KNSIG		64
+#define _NSIG_BPW	64
+
+#define _KNSIG_WORDS	(_KNSIG / _NSIG_BPW)
+
+typedef struct {
+	unsigned long sig[_KNSIG_WORDS];
+} k_rtsigset_t;
+
+static inline void ksigfillset(k_rtsigset_t *set)
+{
+	int i;
+	for (i = 0; i < _KNSIG_WORDS; i++)
+		set->sig[i] = (unsigned long)-1;
+}
+
+#define SA_RESTORER	0x00000000
+
+typedef struct {
+	rt_sighandler_t	rt_sa_handler;
+	unsigned long	rt_sa_flags;
+	rt_sigrestore_t	rt_sa_restorer;
+	k_rtsigset_t	rt_sa_mask;
+} rt_sigaction_t;
+
+/*
+ * Copied from the Linux kernel header arch/arm64/include/uapi/asm/ptrace.h
+ *
+ * A thread ARM CPU context
+ */
+
+typedef struct user_pt_regs user_regs_struct_t;
+
+
+#define ASSIGN_TYPED(a, b) do { a = (typeof(a))b; } while (0)
+#define ASSIGN_MEMBER(a,b,m) do { ASSIGN_TYPED((a)->m, (b)->m); } while (0)
+
+#define REG_RES(regs)		((u64)(regs).regs[0])
+#define REG_IP(regs)		((u64)(regs).pc)
+#define REG_SYSCALL_NR(regs)	((u64)(regs).regs[8])
+
+// Copied from the Linux kernel arch/arm64/include/asm/memory.h
+// FIXME: what about a 32bit task?
+
+#define TASK_SIZE (1ULL << 39)
+
+#define AT_VECTOR_SIZE 40
+
+typedef UserAarch64RegsEntry UserRegsEntry;
+
+#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__AARCH64
+
+#define CORE_THREAD_ARCH_INFO(core) core->ti_aarch64
+
+#define TI_SP(core) ((core)->ti_aarch64->gpregs->sp)
+
+typedef uint64_t auxv_t;
+typedef uint64_t tls_t;
+
+static inline void *decode_pointer(uint64_t v) { return (void*)v; }
+static inline uint64_t encode_pointer(void *p) { return (uint64_t)p; }
+
+#endif /* __CR_ASM_TYPES_H__ */
diff --git a/arch/aarch64/include/asm/vdso.h b/arch/aarch64/include/asm/vdso.h
new file mode 100644
index 0000000..7efbd0a
--- /dev/null
+++ b/arch/aarch64/include/asm/vdso.h
@@ -0,0 +1,47 @@
+#ifndef __CR_ASM_VDSO_H__
+#define __CR_ASM_VDSO_H__
+
+#include <sys/types.h>
+
+#include "protobuf/vma.pb-c.h"
+
+struct vdso_symtable;
+struct parasite_ctl;
+struct vm_area_list;
+
+
+enum {
+	VDSO_SYMBOL_CLOCK_GETRES,
+	VDSO_SYMBOL_CLOCK_GETTIME,
+	VDSO_SYMBOL_GETTIMEOFDAY,
+	VDSO_SYMBOL_RT_SIGRETURN,
+
+	VDSO_SYMBOL_MAX
+};
+
+#define VDSO_SYMBOL_CLOCK_GETRES_NAME	"__kernel_clock_getres"
+#define VDSO_SYMBOL_CLOCK_GETTIME_NAME	"__kernel_clock_gettime"
+#define VDSO_SYMBOL_GETTIMEOFDAY_NAME	"__kernel_gettimeofday"
+#define VDSO_SYMBOL_RT_SIGRETURN_NAME	"__kernel_rt_sigreturn"
+
+
+#define DECLARE_VDSO(ident_name, symtab_name)				\
+									\
+char ident_name[] = {							\
+	0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,			\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,			\
+};									\
+									\
+char *symtab_name[VDSO_SYMBOL_MAX] = {					\
+	[VDSO_SYMBOL_CLOCK_GETRES] = VDSO_SYMBOL_CLOCK_GETRES_NAME,	\
+	[VDSO_SYMBOL_RT_SIGRETURN] = VDSO_SYMBOL_RT_SIGRETURN_NAME,	\
+	[VDSO_SYMBOL_GETTIMEOFDAY] = VDSO_SYMBOL_GETTIMEOFDAY_NAME,	\
+	[VDSO_SYMBOL_CLOCK_GETTIME] = VDSO_SYMBOL_CLOCK_GETTIME_NAME	\
+};
+
+
+extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
+extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
+			       struct vm_area_list *vma_area_list);
+
+#endif /* __CR_ASM_VDSO_H__ */
diff --git a/arch/aarch64/parasite-head.S b/arch/aarch64/parasite-head.S
new file mode 100644
index 0000000..7a35906
--- /dev/null
+++ b/arch/aarch64/parasite-head.S
@@ -0,0 +1,21 @@
+#include "asm/linkage.h"
+#include "parasite.h"
+
+	.section .head.text, "ax"
+ENTRY(__export_parasite_head_start)
+	adr	x2, __export_parasite_head_start	// get the address of this instruction
+
+	ldr	x0, __export_parasite_cmd
+
+	ldr	x1, parasite_args_ptr
+	add	x1, x1, x2				// fixup __export_parasite_args
+
+	bl	parasite_service
+	brk	#0					// the instruction BRK #0 generates the signal SIGTRAP in Linux
+
+parasite_args_ptr:
+	.quad	__export_parasite_args
+
+__export_parasite_cmd:
+	.quad	0
+END(__export_parasite_head_start)
diff --git a/arch/aarch64/restorer.c b/arch/aarch64/restorer.c
new file mode 100644
index 0000000..2c61e2d
--- /dev/null
+++ b/arch/aarch64/restorer.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+
+#include "restorer.h"
+#include "asm/restorer.h"
+#include "asm/string.h"
+
+#include "syscall.h"
+#include "log.h"
+#include "asm/fpu.h"
+#include "cpu.h"
+
+int restore_nonsigframe_gpregs(UserRegsEntry *r)
+{
+	return 0;
+}
diff --git a/arch/aarch64/syscall-common.S b/arch/aarch64/syscall-common.S
new file mode 100644
index 0000000..81ec20f
--- /dev/null
+++ b/arch/aarch64/syscall-common.S
@@ -0,0 +1,19 @@
+#include "asm/linkage.h"
+
+syscall_common:
+	svc	#0
+	ret
+
+
+.macro syscall name, nr
+	ENTRY(\name)
+		mov	x8, \nr
+		b	syscall_common
+	END(\name)
+.endm
+
+
+ENTRY(__cr_restore_rt)
+	mov	x8, __NR_rt_sigreturn
+	svc	#0
+END(__cr_restore_rt)
diff --git a/arch/aarch64/vdso-pie.c b/arch/aarch64/vdso-pie.c
new file mode 100644
index 0000000..c96fc25
--- /dev/null
+++ b/arch/aarch64/vdso-pie.c
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <elf.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "asm/string.h"
+#include "asm/types.h"
+
+#include "compiler.h"
+#include "syscall.h"
+#include "crtools.h"
+#include "vdso.h"
+#include "vma.h"
+#include "log.h"
+
+#ifdef LOG_PREFIX
+# undef LOG_PREFIX
+#endif
+#define LOG_PREFIX "vdso: "
+
+
+int vdso_redirect_calls(void *base_to, void *base_from,
+			struct vdso_symtable *to,
+			struct vdso_symtable *from)
+{
+	pr_err("vDSO proxy isn't implemented yet");
+	return -1;
+}
diff --git a/arch/aarch64/vdso.c b/arch/aarch64/vdso.c
new file mode 100644
index 0000000..5053acf
--- /dev/null
+++ b/arch/aarch64/vdso.c
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <elf.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "parasite-syscall.h"
+#include "parasite.h"
+#include "compiler.h"
+#include "kerndat.h"
+#include "vdso.h"
+#include "util.h"
+#include "log.h"
+#include "mem.h"
+#include "vma.h"
+
+#include "asm/types.h"
+#include "asm/parasite-syscall.h"
+
+
+#ifdef LOG_PREFIX
+# undef LOG_PREFIX
+#endif
+#define LOG_PREFIX "vdso: "
+
+
+int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
+			struct vm_area_list *vma_area_list)
+{
+	return 0;
+}
-- 
1.7.9.5



More information about the CRIU mailing list