[CRIU] [PATCH 3/3] arm: added ARM-specific files modelled after arch/x86

Alexander Kartashov alekskartashov at parallels.com
Tue Jan 22 03:51:19 EST 2013


Signed-off-by: Alexander Kartashov <alekskartashov at parallels.com>
---
 Makefile                                    |    7 +
 arch/arm/Makefile                           |   57 ++++++
 arch/arm/crtools.c                          |  232 +++++++++++++++++++++++++
 arch/arm/gen-sys-exec-tbl.pl                |   39 +++++
 arch/arm/gen-syscalls.pl                    |  104 +++++++++++
 arch/arm/include/asm/atomic.h               |   67 ++++++++
 arch/arm/include/asm/bitops.h               |  111 ++++++++++++
 arch/arm/include/asm/dump.h                 |   14 ++
 arch/arm/include/asm/linkage.h              |   24 +++
 arch/arm/include/asm/memcpy_64.h            |   20 +++
 arch/arm/include/asm/parasite-syscall.h     |   18 ++
 arch/arm/include/asm/parasite.h             |   28 +++
 arch/arm/include/asm/processor-flags.h      |   42 +++++
 arch/arm/include/asm/restore.h              |   25 +++
 arch/arm/include/asm/restorer.h             |  147 ++++++++++++++++
 arch/arm/include/asm/syscall-aux.S          |    9 +
 arch/arm/include/asm/syscall-aux.h          |    8 +
 arch/arm/include/asm/types.h                |  248 +++++++++++++++++++++++++++
 arch/arm/parasite-head.S                    |   24 +++
 arch/arm/restorer.c                         |   50 ++++++
 arch/arm/syscall-common.S                   |   52 ++++++
 arch/arm/syscall.def                        |   78 +++++++++
 arch/arm/uidiv.S                            |  186 ++++++++++++++++++++
 test/zdtm/lib/arch/arm/include/asm/atomic.h |   66 +++++++
 24 files changed, 1656 insertions(+)
 create mode 100644 arch/arm/Makefile
 create mode 100644 arch/arm/crtools.c
 create mode 100755 arch/arm/gen-sys-exec-tbl.pl
 create mode 100755 arch/arm/gen-syscalls.pl
 create mode 100644 arch/arm/include/asm/atomic.h
 create mode 100644 arch/arm/include/asm/bitops.h
 create mode 100644 arch/arm/include/asm/dump.h
 create mode 100644 arch/arm/include/asm/linkage.h
 create mode 100644 arch/arm/include/asm/memcpy_64.h
 create mode 100644 arch/arm/include/asm/parasite-syscall.h
 create mode 100644 arch/arm/include/asm/parasite.h
 create mode 100644 arch/arm/include/asm/processor-flags.h
 create mode 100644 arch/arm/include/asm/restore.h
 create mode 100644 arch/arm/include/asm/restorer.h
 create mode 100644 arch/arm/include/asm/syscall-aux.S
 create mode 100644 arch/arm/include/asm/syscall-aux.h
 create mode 100644 arch/arm/include/asm/types.h
 create mode 100644 arch/arm/parasite-head.S
 create mode 100644 arch/arm/restorer.c
 create mode 100644 arch/arm/syscall-common.S
 create mode 100644 arch/arm/syscall.def
 create mode 100644 arch/arm/uidiv.S
 create mode 100644 test/zdtm/lib/arch/arm/include/asm/atomic.h

diff --git a/Makefile b/Makefile
index d203845..9c512d5 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,13 @@ ifeq ($(uname_M),x86_64)
 	LDARCH       := i386:x86-64
 endif
 
+ifeq ($(findstring arm,$(uname_M)),arm)
+	ARCH         := arm
+	ARCH_DEFINES := -DCONFIG_ARM
+	LDARCH       := arm
+	CFLAGS       += -march=armv7-a
+endif
+
 SRC_DIR		?= $(shell pwd)
 ARCH_DIR	:= $(SRC_DIR)/arch/$(ARCH)
 
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
new file mode 100644
index 0000000..847e106
--- /dev/null
+++ b/arch/arm/Makefile
@@ -0,0 +1,57 @@
+SYS-DEF		:= $(ARCH_DIR)/syscall.def
+SYS-ASM-COMMON	:= syscall-common.S
+SYS-TYPES	:= $(SRC_DIR)/include/syscall-types.h
+
+SYS-CODES	:= $(SRC_DIR)/include/syscall-codes.h
+SYS-PROTO	:= $(SRC_DIR)/include/syscall.h
+
+SYS-ASM		:= syscalls.S
+SYS-GEN		:= $(ARCH_DIR)/gen-syscalls.pl
+SYS-GEN-TBL	:= $(ARCH_DIR)/gen-sys-exec-tbl.pl
+
+SYS-OBJ		:= syscalls.o
+
+SYS-EXEC-TBL	:= sys-exec-tbl.c
+
+CFLAGS		+= -c -fpie -Wstrict-prototypes -Wa,--noexecstack -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -I$(shell pwd)
+
+ARCH_BITS	:= 32
+
+.DEFAULT_GOAL	:= arm
+
+$(SYS-ASM): $(SYS-GEN) $(SYS-DEF) $(SYS-ASM-COMMON) $(SYS-TYPES)
+	$(E) "  GEN     " $@
+	$(Q) perl			\
+		$(SYS-GEN)		\
+		$(SYS-DEF)		\
+		$(SYS-CODES)		\
+		$(SYS-PROTO)		\
+		$(SYS-ASM)		\
+		$(SYS-ASM-COMMON)	\
+		$(SYS-TYPES)		\
+		$(ARCH_BITS)
+
+$(SYS-EXEC-TBL): $(SYS-GEN-TBL) $(SYS-DEF)
+	$(E) "  GEN     " $@
+	$(Q) perl			\
+		$(SYS-GEN-TBL)		\
+		$(SYS-DEF)		\
+		$(SYS-EXEC-TBL)		\
+		$(ARCH_BITS)
+
+%.o: %.S
+	$(E) "  CC      " $@
+	$(Q) $(CC) $(CFLAGS)  $^ -o $@
+
+arm: $(SYS-OBJ) $(SYS-EXEC-TBL)
+
+clean:
+	$(E) "  CLEAN SYSCALLS"
+	$(Q) $(RM) -f $(SYS-ASM)
+	$(Q) $(RM) -f $(SYS-CODES)
+	$(Q) $(RM) -f $(SYS-PROTO)
+	$(Q) $(RM) -f $(SYS-OBJ)
+	$(Q) $(RM) -f $(SYS-EXEC-TBL)
+	$(Q) $(RM) -f *.o *.d
+
+.PHONY: clean arm
diff --git a/arch/arm/crtools.c b/arch/arm/crtools.c
new file mode 100644
index 0000000..c1ee5dc
--- /dev/null
+++ b/arch/arm/crtools.c
@@ -0,0 +1,232 @@
+#include <string.h>
+#include <unistd.h>
+
+#include "asm/types.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 "fpu.h"
+#include "elf.h"
+#include "parasite-syscall.h"
+#include "restorer.h"
+
+
+/*
+ * Injected syscall instruction
+ */
+const char code_syscall[] = {
+	0x00, 0x00, 0x00, 0xef,         /* SVC #0  */
+	0xf0, 0x01, 0xf0, 0xe7          /* UDF #32 */
+};
+
+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, user_regs_struct_t *regs)
+{
+	regs->ARM_pc = new_ip;
+
+	/* Avoid end of syscall processing */
+	regs->ARM_ORIG_r0 = -1;
+
+	/* Make sure flags are in known state */
+	regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT;
+}
+
+
+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->regs_orig;
+	int err;
+
+	regs.ARM_r7 = (unsigned long)nr;
+	regs.ARM_r0 = arg1;
+	regs.ARM_r1 = arg2;
+	regs.ARM_r2 = arg3;
+	regs.ARM_r3 = arg4;
+	regs.ARM_r4 = arg5;
+	regs.ARM_r5 = arg6;
+
+	parasite_setup_regs(ctl->syscall_ip, &regs);
+	err = __parasite_execute(ctl, ctl->pid, &regs);
+	if (err)
+		return err;
+
+	*ret = regs.ARM_r0;
+	return 0;
+}
+
+#define assign_reg(dst, src, e)		dst->e = (__typeof__(dst->e))src.ARM_##e
+
+int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
+{
+	user_regs_struct_t regs = {{-1}};
+	struct user_vfp vfp;
+	int ret = -1;
+
+	pr_info("Dumping GP/FPU registers ... ");
+
+	if (ctl)
+		regs = ctl->regs_orig;
+	else {
+		if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
+			pr_err("Can't obtain GP registers for %d\n", pid);
+			goto err;
+		}
+	}
+
+	if (ptrace(PTRACE_GETFPREGS, pid, NULL, &vfp)) {
+		pr_err("Can't obtain FPU registers for %d\n", 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;
+		}
+	}
+
+
+	// Save the ARM CPU state
+
+	assign_reg(core->ti_arm->gpregs, regs, r0);
+	assign_reg(core->ti_arm->gpregs, regs, r1);
+	assign_reg(core->ti_arm->gpregs, regs, r2);
+	assign_reg(core->ti_arm->gpregs, regs, r3);
+	assign_reg(core->ti_arm->gpregs, regs, r4);
+	assign_reg(core->ti_arm->gpregs, regs, r5);
+	assign_reg(core->ti_arm->gpregs, regs, r6);
+	assign_reg(core->ti_arm->gpregs, regs, r7);
+	assign_reg(core->ti_arm->gpregs, regs, r8);
+	assign_reg(core->ti_arm->gpregs, regs, r9);
+	assign_reg(core->ti_arm->gpregs, regs, r10);
+	assign_reg(core->ti_arm->gpregs, regs, fp);
+	assign_reg(core->ti_arm->gpregs, regs, ip);
+	assign_reg(core->ti_arm->gpregs, regs, sp);
+	assign_reg(core->ti_arm->gpregs, regs, lr);
+	assign_reg(core->ti_arm->gpregs, regs, pc);
+	assign_reg(core->ti_arm->gpregs, regs, cpsr);
+	core->ti_arm->gpregs->orig_r0 = regs.ARM_ORIG_r0;
+
+
+	// Save the VFP state
+
+	memcpy(CORE_THREAD_ARCH_INFO(core)->fpstate->vfp_regs, &vfp.fpregs, sizeof(vfp.fpregs));
+	CORE_THREAD_ARCH_INFO(core)->fpstate->fpscr = vfp.fpscr;
+
+	ret = 0;
+
+err:
+	return ret;
+}
+
+int arch_alloc_thread_info(CoreEntry *core)
+{
+	ThreadInfoArm *ti_arm;
+	UserArmRegsEntry *gpregs;
+	UserArmVfpstateEntry *fpstate;
+	ThreadCoreEntry *thread_core;
+
+	ti_arm = xmalloc(sizeof(*ti_arm));
+	if (!ti_arm)
+		goto err;
+	thread_info_arm__init(ti_arm);
+
+	gpregs = xmalloc(sizeof(*gpregs));
+	user_arm_regs_entry__init(gpregs);
+	ti_arm->gpregs = gpregs;
+
+	fpstate = xmalloc(sizeof(*fpstate));
+	user_arm_vfpstate_entry__init(fpstate);
+	fpstate->vfp_regs = xmalloc(32*sizeof(unsigned long long));
+	fpstate->n_vfp_regs = 32;
+	ti_arm->fpstate = fpstate;
+
+	core->ti_arm = ti_arm;
+
+
+	thread_core = xmalloc(sizeof(*thread_core));
+	if (!thread_core)
+		goto err;
+	thread_core_entry__init(thread_core);
+	core->thread_core = thread_core;
+
+err:
+	return 0;
+}
+
+void core_entry_free(CoreEntry *core)
+{
+	if (core) {
+		if (CORE_THREAD_ARCH_INFO(core)) {
+			if (CORE_THREAD_ARCH_INFO(core)->fpstate) {
+				xfree(CORE_THREAD_ARCH_INFO(core)->fpstate->vfp_regs);
+				xfree(CORE_THREAD_ARCH_INFO(core)->fpstate);
+			}
+			xfree(CORE_THREAD_ARCH_INFO(core)->gpregs);
+		}
+		xfree(CORE_THREAD_ARCH_INFO(core));
+		xfree(core->thread_core);
+		xfree(core->tc);
+		xfree(core->ids);
+	}
+
+}
+
+int sigreturn_prep_fpu_frame(struct thread_restore_args *args, CoreEntry *core)
+{
+	memcpy(args->fpu_state.ufp.fpregs, CORE_THREAD_ARCH_INFO(core)->fpstate->vfp_regs,
+		sizeof(args->fpu_state.ufp.fpregs));
+	args->fpu_state.ufp.fpscr = CORE_THREAD_ARCH_INFO(core)->fpstate->fpscr;
+
+	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;
+
+	if (offset & ~PAGE_MASK)
+		return 0;
+
+	err = syscall_seized(ctl, __NR_mmap2, &map,
+			(unsigned long)addr, length, prot, flags, fd, offset >> 12);
+	if (err < 0 || map > TASK_SIZE)
+		map = 0;
+
+	return (void *)map;
+}
diff --git a/arch/arm/gen-sys-exec-tbl.pl b/arch/arm/gen-sys-exec-tbl.pl
new file mode 100755
index 0000000..1746a0c
--- /dev/null
+++ b/arch/arm/gen-sys-exec-tbl.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $in		= $ARGV[0];
+my $tblout	= $ARGV[1];
+my $bits	= $ARGV[2];
+
+my $code	= "code$bits";
+
+open TBLOUT,	">", $tblout	or die $!;
+open IN,		"<", $in		or die $!;
+
+print TBLOUT "/* Autogenerated, don't edit */\n";
+
+for (<IN>) {
+	if ($_ =~ /\#/) {
+		next;
+	}
+
+	my $sys_name;
+	my $sys_num;
+
+	if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
+		$sys_name = $+{alias};
+	} elsif (/(?<name>\S+)\s+(?<code64>\d+)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
+		$sys_name = $+{name};
+	} else {
+		unlink $tblout;
+		die "Invalid syscall definition file: invalid entry $_\n";
+	}
+
+	$sys_num = $+{$code};
+
+	if ($sys_num ne "!") {
+		print TBLOUT "SYSCALL($sys_name, $sys_num)\n";
+	}
+}
diff --git a/arch/arm/gen-syscalls.pl b/arch/arm/gen-syscalls.pl
new file mode 100755
index 0000000..4b65621
--- /dev/null
+++ b/arch/arm/gen-syscalls.pl
@@ -0,0 +1,104 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $in         = $ARGV[0];
+my $codesout   = $ARGV[1];
+my $codes      = $ARGV[1] =~ s/.*include\///gr;
+my $protosout  = $ARGV[2];
+my $protos     = $ARGV[2] =~ s/.*include\///gr;
+my $asmout     = $ARGV[3];
+my $asmcommon  = $ARGV[4];
+my $prototypes = $ARGV[5] =~ s/.*include\///gr;
+my $bits       = $ARGV[6];
+
+my $codesdef   = $codes =~ tr/.-/_/r;
+my $protosdef  = $protos =~ tr/.-/_/r;
+my $code       = "code$bits";
+my $need_aux   = 0;
+
+unlink $codesout;
+unlink $protosout;
+unlink $asmout;
+
+open CODESOUT,	">", $codesout	or die $!;
+open PROTOSOUT, ">", $protosout or die $!;
+open ASMOUT,	">", $asmout	or die $!;
+open IN,	"<", $in	or die $!;
+
+print CODESOUT <<"END";
+/* Autogenerated, don't edit */
+#ifndef $codesdef
+#define $codesdef
+END
+
+print PROTOSOUT <<"END";
+/* Autogenerated, don't edit */
+#ifndef $protosdef
+#define $protosdef
+#include "$prototypes"
+#include "$codes"
+END
+
+print ASMOUT <<"END";
+/* Autogenerated, don't edit */
+#include "$codes"
+#include "$asmcommon"
+END
+
+
+for (<IN>) {
+	if ($_ =~ /\#/) {
+		next;
+	}
+
+	my $code_macro;
+	my $sys_name;
+
+	if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
+		$code_macro = "__NR_$+{name}";
+		$sys_name   = "sys_$+{alias}";
+	} elsif (/(?<name>\S+)\s+(?<code64>\d+)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
+		$code_macro = "__NR_$+{name}";
+		$sys_name   = "sys_$+{name}";
+	} else {
+		unlink $codesout;
+		unlink $protosout;
+		unlink $asmout;
+
+		die "Invalid syscall definition file: invalid entry $_\n";
+	}
+
+	if ($+{$code} ne "!") {
+		print CODESOUT "#define $code_macro $+{$code}\n";
+
+		my $nargs;
+
+		if ($+{args} eq "void") {
+			$nargs = 0;
+		} else {
+			my $tmp = $+{args};
+			$nargs = 1 + ($tmp =~ tr/\,/\,/);
+
+			if ($nargs <= 4) {
+			$nargs = 0;
+		}
+	}
+
+	print ASMOUT "syscall$nargs $sys_name, $code_macro\n";
+
+	} else {
+		$need_aux = 1;
+	}
+
+	print PROTOSOUT "extern long $sys_name($+{args});\n";
+}
+
+if ($need_aux == 1) {
+	print ASMOUT   "#include \"asm/syscall-aux.S\"\n";
+	print CODESOUT "#include \"asm/syscall-aux.h\"\n";
+}
+
+print CODESOUT  "#endif /* $codesdef */";
+print PROTOSOUT "#endif /* $protosdef */";
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
new file mode 100644
index 0000000..ccf6a7d
--- /dev/null
+++ b/arch/arm/include/asm/atomic.h
@@ -0,0 +1,67 @@
+#ifndef __CR_ATOMIC_H__
+#define __CR_ATOMIC_H__
+
+typedef struct {
+	u32 counter;
+} atomic_t;
+
+
+/* Copied from the Linux kernel header arch/arm/include/asm/atomic.h */
+
+#define smp_mb() __asm__ __volatile__ ("dmb" : : : "memory")
+
+#define atomic_set(mem,v) ((mem)->counter = (v))
+#define atomic_get(v)	(*(volatile u32 *)&(v)->counter)
+
+static inline unsigned int atomic_add_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	unsigned int result;
+
+	smp_mb();
+
+	__asm__ __volatile__("@ atomic_add_return\n"
+"1:	ldrex	%0, [%3]\n"
+"	add	%0, %0, %4\n"
+"	strex	%1, %0, [%3]\n"
+"	teq	%1, #0\n"
+"	bne	1b\n"
+	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
+        : "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	smp_mb();
+
+	return result;
+}
+
+static inline unsigned int atomic_sub_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	smp_mb();
+
+	__asm__ __volatile__("@ atomic_sub_return\n"
+"1:	ldrex	%0, [%3]\n"
+"	sub	%0, %0, %4\n"
+"	strex	%1, %0, [%3]\n"
+"	teq	%1, #0\n"
+"	bne	1b\n"
+	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
+	: "r" (&v->counter), "Ir" (i)
+	: "cc");
+
+	smp_mb();
+
+	return result;
+}
+
+static inline unsigned int atomic_inc(atomic_t *v) { return atomic_add_return(1, v) - 1; }
+
+static inline unsigned 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)
+
+#endif /* __CR_ATOMIC_H__ */
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h
new file mode 100644
index 0000000..5aa218d
--- /dev/null
+++ b/arch/arm/include/asm/bitops.h
@@ -0,0 +1,111 @@
+#ifndef __CR_BITOPS_H__
+#define __CR_BITOPS_H__
+
+#define DIV_ROUND_UP(n,d)	(((n) + (d) - 1) / (d))
+#define BITS_PER_LONG		(8 * sizeof(long))
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
+
+#define DECLARE_BITMAP(name, bits)		\
+	unsigned long name[BITS_TO_LONGS(bits)]
+
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
+/* Technically wrong, but this avoids compilation errors on some gcc
+   versions. */
+#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
+#else
+#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
+#endif
+
+#define ADDR				BITOP_ADDR(addr)
+
+static inline void set_bit(int nr, volatile unsigned long *addr) {
+	*addr |= (1 << nr);
+}
+
+static inline void change_bit(int nr, volatile unsigned long *addr)
+{
+	*addr ^= (1 << nr);
+}
+
+static inline int test_bit(int nr, volatile const unsigned long *addr)
+{
+	return (*addr & (1 << nr)) ? -1 : 0;
+}
+
+static inline void clear_bit(int nr, volatile unsigned long *addr)
+{
+	*addr &= ~(1 << nr);
+}
+
+/**
+ * __ffs - find first set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+	int p = 0;
+
+	for (; p < 8*sizeof(word); ++p) {
+		if (word & 1) {
+			break;
+		}
+
+		word >>= 1;
+	}
+
+	return p;
+}
+
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/*
+ * Find the next set bit in a memory region.
+ */
+static inline
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+			    unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
+	if (offset) {
+		tmp = *(p++);
+		tmp &= (~0UL << offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1)) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp &= (~0UL >> (BITS_PER_LONG - size));
+	if (tmp == 0UL)		/* Are any bits set? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + __ffs(tmp);
+}
+
+#define for_each_bit(i, bitmask)				\
+	for (i = find_next_bit(bitmask, sizeof(bitmask), 0);	\
+	     i < sizeof(bitmask);				\
+	     i = find_next_bit(bitmask, sizeof(bitmask), i + 1))
+
+#endif /* __CR_BITOPS_H__ */
diff --git a/arch/arm/include/asm/dump.h b/arch/arm/include/asm/dump.h
new file mode 100644
index 0000000..d8d0ae1
--- /dev/null
+++ b/arch/arm/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, CoreEntry *core, const struct parasite_ctl *ctl);
+extern int arch_alloc_thread_info(CoreEntry *core);
+extern void core_entry_free(CoreEntry *core);
+
+
+static inline void core_put_tls(CoreEntry *core, u32 tls)
+{
+	core->ti_arm->tls = tls;
+}
+
+#endif
diff --git a/arch/arm/include/asm/linkage.h b/arch/arm/include/asm/linkage.h
new file mode 100644
index 0000000..7380642
--- /dev/null
+++ b/arch/arm/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/arm/include/asm/memcpy_64.h b/arch/arm/include/asm/memcpy_64.h
new file mode 100644
index 0000000..3dc8f34
--- /dev/null
+++ b/arch/arm/include/asm/memcpy_64.h
@@ -0,0 +1,20 @@
+#ifndef __MEMCPY_ARM_H__
+#define __MEMCPY_ARM_H__
+
+#include "compiler.h"
+#include "types.h"
+
+static always_inline void *builtin_memcpy(void *to, const void *from, unsigned int n)
+{
+	int i;
+	unsigned char *cto = to;
+	const unsigned char *cfrom = from;
+
+	for (i = 0; i < n; ++i, ++cto, ++cfrom) {
+		*cto = *cfrom;
+	}
+
+	return to;
+}
+
+#endif
diff --git a/arch/arm/include/asm/parasite-syscall.h b/arch/arm/include/asm/parasite-syscall.h
new file mode 100644
index 0000000..8971277
--- /dev/null
+++ b/arch/arm/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, 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/arm/include/asm/parasite.h b/arch/arm/include/asm/parasite.h
new file mode 100644
index 0000000..3ea6e34
--- /dev/null
+++ b/arch/arm/include/asm/parasite.h
@@ -0,0 +1,28 @@
+#ifndef __ASM_PARASITE_H__
+#define __ASM_PARASITE_H__
+
+static inline u32 arch_get_tls(void) {
+	uint32_t res;
+
+	asm (
+	     "adr %%r1, 1f              \n"
+	     "ldr %%r1, [%%r1]          \n"
+	     "push { %%r7, %%lr }       \n"
+	     "blx %%r1                  \n"
+	     "pop { %%r7, %%lr }        \n"
+	     "mov %0, %%r0              \n"
+	     "b   2f                    \n"
+
+	     "1:                        \n"
+	     ".word 0xffff0fe0          \n"
+
+	     "2:                        \n"
+	     :"=r"(res)
+	     :
+	     : "r0", "r1", "memory"
+	     );
+
+	return res;
+}
+
+#endif
diff --git a/arch/arm/include/asm/processor-flags.h b/arch/arm/include/asm/processor-flags.h
new file mode 100644
index 0000000..fc00a9e
--- /dev/null
+++ b/arch/arm/include/asm/processor-flags.h
@@ -0,0 +1,42 @@
+#ifndef __CR_PROCESSOR_FLAGS_H__
+#define __CR_PROCESSOR_FLAGS_H__
+
+/* Copied from the Linux kernel header arch/arm/include/uapi/asm/ptrace.h */
+
+/*
+ * PSR bits
+ */
+#define USR26_MODE      0x00000000
+#define FIQ26_MODE      0x00000001
+#define IRQ26_MODE      0x00000002
+#define SVC26_MODE      0x00000003
+#define USR_MODE        0x00000010
+#define FIQ_MODE        0x00000011
+#define IRQ_MODE        0x00000012
+#define SVC_MODE        0x00000013
+#define ABT_MODE        0x00000017
+#define UND_MODE        0x0000001b
+#define SYSTEM_MODE     0x0000001f
+#define MODE32_BIT      0x00000010
+#define MODE_MASK       0x0000001f
+#define PSR_T_BIT       0x00000020
+#define PSR_F_BIT       0x00000040
+#define PSR_I_BIT       0x00000080
+#define PSR_A_BIT       0x00000100
+#define PSR_E_BIT       0x00000200
+#define PSR_J_BIT       0x01000000
+#define PSR_Q_BIT       0x08000000
+#define PSR_V_BIT       0x10000000
+#define PSR_C_BIT       0x20000000
+#define PSR_Z_BIT       0x40000000
+#define PSR_N_BIT       0x80000000
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f           0xff000000      /* Flags                */
+#define PSR_s           0x00ff0000      /* Status               */
+#define PSR_x           0x0000ff00      /* Extension            */
+#define PSR_c           0x000000ff      /* Control              */
+
+#endif
diff --git a/arch/arm/include/asm/restore.h b/arch/arm/include/asm/restore.h
new file mode 100644
index 0000000..c30d91a
--- /dev/null
+++ b/arch/arm/include/asm/restore.h
@@ -0,0 +1,25 @@
+#ifndef __CR_ASM_RESTORE_H__
+#define __CR_ASM_RESTORE_H__
+
+#define JUMP_TO_RESTORER_BLOB(new_sp, restore_task_exec_start,          \
+			      task_args)				\
+	asm volatile(							\
+		     "mov %%sp, %%%0				    \n" \
+		     "mov %%r1, %%%1				    \n" \
+		     "mov %%r0, %%%2				    \n" \
+		     "bx  %%r1				            \n"	\
+		     :							\
+		     : "r"(new_sp),					\
+		       "r"(restore_task_exec_start),			\
+		       "r"(task_args)					\
+		     : "sp", "r0", "r1", "memory")
+
+static inline void core_get_tls(CoreEntry *pcore, u32 *ptls)
+{
+	*ptls = pcore->ti_arm->tls;
+}
+
+
+int sigreturn_prep_fpu_frame(struct thread_restore_args *args, CoreEntry *core);
+
+#endif
diff --git a/arch/arm/include/asm/restorer.h b/arch/arm/include/asm/restorer.h
new file mode 100644
index 0000000..ea93255
--- /dev/null
+++ b/arch/arm/include/asm/restorer.h
@@ -0,0 +1,147 @@
+#ifndef __CR_ASM_RESTORER_H__
+#define __CR_ASM_RESTORER_H__
+
+#include "asm/types.h"
+#include "../protobuf/core.pb-c.h"
+
+/* Copied from the Linux kernel header arch/arm/include/asm/sigcontext.h */
+
+struct rt_sigcontext {
+	unsigned long trap_no;
+	unsigned long error_code;
+	unsigned long oldmask;
+	unsigned long arm_r0;
+	unsigned long arm_r1;
+	unsigned long arm_r2;
+	unsigned long arm_r3;
+	unsigned long arm_r4;
+	unsigned long arm_r5;
+	unsigned long arm_r6;
+	unsigned long arm_r7;
+	unsigned long arm_r8;
+	unsigned long arm_r9;
+	unsigned long arm_r10;
+	unsigned long arm_fp;
+	unsigned long arm_ip;
+	unsigned long arm_sp;
+	unsigned long arm_lr;
+	unsigned long arm_pc;
+	unsigned long arm_cpsr;
+	unsigned long fault_address;
+};
+
+/* Copied from the Linux kernel header arch/arm/include/asm/ucontext.h */
+
+#define VFP_MAGIC               0x56465001
+#define VFP_STORAGE_SIZE        sizeof(struct vfp_sigframe)
+
+struct vfp_sigframe {
+	unsigned long           magic;
+	unsigned long           size;
+	struct user_vfp         ufp;
+	struct user_vfp_exc     ufp_exc;
+};
+
+struct aux_sigframe {
+	/*
+	struct crunch_sigframe  crunch;
+        struct iwmmxt_sigframe  iwmmxt;
+	*/
+
+	struct vfp_sigframe     vfp;
+	unsigned long           end_magic;
+} __attribute__((__aligned__(8)));
+
+#include "sigframe.h"
+
+struct sigframe {
+	struct rt_ucontext uc;
+	unsigned long retcode[2];
+};
+
+struct rt_sigframe {
+	struct rt_siginfo info;
+	struct sigframe sig;
+};
+
+
+#define ARCH_RT_SIGRETURN(new_sp)					\
+	asm volatile(							\
+		     "mov %%sp, %0				    \n"	\
+		     "mov %%r7,  #"__stringify(__NR_rt_sigreturn)"  \n" \
+		     "svc #0					    \n"	\
+		     :							\
+		     : "r"(new_sp)					\
+		     : "sp","memory")
+
+#define RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, 	\
+			     thread_args, clone_restore_fn)		\
+	asm volatile(							\
+		     "clone_emul:				\n"	\
+		     "ldr %%r1, %2				\n"	\
+		     "sub %%r1, #16			        \n"	\
+		     "mov %%r0, %%%6				\n"	\
+		     "str %%r0, [%%r1, #4]			\n"	\
+		     "mov %%r0, %%%5				\n"	\
+		     "str %%r0, [%%r1]			        \n"	\
+		     "mov %%r0, %%%1				\n"	\
+		     "mov %%r2, %%%3				\n"	\
+		     "mov %%r3, %%%4				\n"	\
+		     "mov %%r7, #"__stringify(__NR_clone)"	\n"	\
+		     "svc #0				        \n"	\
+									\
+		     "cmp %%r0, #0			        \n"	\
+		     "beq thread_run				\n"	\
+									\
+		     "mov %%%0, %%r0				\n"	\
+		     "b   clone_end				\n"	\
+									\
+		     "thread_run:				\n"	\
+		     "pop { %%r1 }			        \n"	\
+		     "pop { %%r0 }			        \n"	\
+		     "bx  %%r1				        \n"	\
+									\
+		     "clone_end:				\n"	\
+		     : "=r"(ret)					\
+		     : "r"(clone_flags),				\
+		       "m"(new_sp),					\
+		       "r"(&parent_tid),				\
+		       "r"(&thread_args[i].pid),			\
+		       "r"(clone_restore_fn),				\
+		       "r"(&thread_args[i])				\
+		     : "r0", "r1", "r2", "r3", "r7", "memory")
+
+#define ARCH_FAIL_CORE_RESTORE					\
+	asm volatile(						\
+		     "mov %%sp, %0			    \n"	\
+		     "mov %%r0, #0			    \n"	\
+		     "bx  %%r0			            \n"	\
+		     :						\
+		     : "r"(ret)					\
+		     : "memory")
+
+
+#define RT_SIGFRAME_UC(rt_sigframe) rt_sigframe->sig.uc
+
+#define SIGFRAME_OFFSET 0
+
+
+int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r);
+
+int restore_fpu(struct rt_sigframe *sigframe, struct thread_restore_args *args);
+
+static inline void restore_tls(u32 tls) {
+	asm (
+	     "mov %%r7, #15  \n"
+	     "lsl %%r7, #16  \n"
+	     "mov %%r0, #5   \n"
+	     "add %%r7, %%r0 \n"	/* r7 = 0xF005 */
+	     "mov %%r0, %0   \n"
+	     "svc #0         \n"
+	     :
+	     : "r"(tls)
+	     : "r0", "r7"
+	     );
+}
+
+#endif
diff --git a/arch/arm/include/asm/syscall-aux.S b/arch/arm/include/asm/syscall-aux.S
new file mode 100644
index 0000000..77e1397
--- /dev/null
+++ b/arch/arm/include/asm/syscall-aux.S
@@ -0,0 +1,9 @@
+        ENTRY(sys_mmap)
+        push    { %r4, %r5, %r7 }
+        ldr     %r4, [%sp, #12]
+        ldr     %r5, [%sp, #16]
+	lsr	%r5, #12
+        do_sys  192
+        pop     { %r4, %r5, %r7 }
+        bx      %lr
+        END(sys_mmap)
\ No newline at end of file
diff --git a/arch/arm/include/asm/syscall-aux.h b/arch/arm/include/asm/syscall-aux.h
new file mode 100644
index 0000000..ec8c2d3
--- /dev/null
+++ b/arch/arm/include/asm/syscall-aux.h
@@ -0,0 +1,8 @@
+#define __NR_mmap2 192
+
+#define __ARM_NR_BASE                   0x0f0000
+#define __ARM_NR_breakpoint             (__ARM_NR_BASE+1)
+#define __ARM_NR_cacheflush             (__ARM_NR_BASE+2)
+#define __ARM_NR_usr26                  (__ARM_NR_BASE+3)
+#define __ARM_NR_usr32                  (__ARM_NR_BASE+4)
+#define __ARM_NR_set_tls                (__ARM_NR_BASE+5)
diff --git a/arch/arm/include/asm/types.h b/arch/arm/include/asm/types.h
new file mode 100644
index 0000000..d068e51
--- /dev/null
+++ b/arch/arm/include/asm/types.h
@@ -0,0 +1,248 @@
+#ifndef __CR_ASM_TYPES_H__
+#define __CR_ASM_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <signal.h>
+#include "../protobuf/core.pb-c.h"
+
+#include "asm/bitops.h"
+
+/* prctl.h */
+#define PR_SET_NAME		15
+#define PR_GET_NAME		16
+
+#define PR_CAPBSET_DROP		24
+#define PR_GET_SECUREBITS	27
+#define PR_SET_SECUREBITS	28
+
+#define SECURE_NO_SETUID_FIXUP	2
+
+#define PR_SET_MM		35
+# define PR_SET_MM_START_CODE		1
+# define PR_SET_MM_END_CODE		2
+# define PR_SET_MM_START_DATA		3
+# define PR_SET_MM_END_DATA		4
+# define PR_SET_MM_START_STACK		5
+# define PR_SET_MM_START_BRK		6
+# define PR_SET_MM_BRK			7
+# define PR_SET_MM_ARG_START		8
+# define PR_SET_MM_ARG_END		9
+# define PR_SET_MM_ENV_START		10
+# define PR_SET_MM_ENV_END		11
+# define PR_SET_MM_AUXV			12
+# define PR_SET_MM_EXE_FILE		13
+
+#define PR_GET_TID_ADDRESS     40
+
+/* fcntl */
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE	1024
+#endif
+#ifndef F_SETPIPE_SZ
+# define F_SETPIPE_SZ	(F_LINUX_SPECIFIC_BASE + 7)
+#endif
+#ifndef F_GETPIPE_SZ
+# define F_GETPIPE_SZ	(F_LINUX_SPECIFIC_BASE + 8)
+#endif
+
+#ifndef F_GETOWNER_UIDS
+#define F_GETOWNER_UIDS	17
+#endif
+
+#define CLONE_CHILD_USEPID      0x02000000
+#define CLONE_VFORK		0x00004000
+
+#define SIGMAX			64
+#define SIGMAX_OLD		31
+
+#define ERESTARTSYS		512
+#define ERESTARTNOINTR		513
+#define ERESTARTNOHAND		514
+#define ERESTART_RESTARTBLOCK	516
+
+typedef uint64_t		u64;
+typedef int64_t			s64;
+typedef unsigned int		u32;
+typedef signed int		s32;
+typedef unsigned short		u16;
+typedef signed short		s16;
+typedef unsigned char		u8;
+typedef signed char		s8;
+
+#define MAJOR(dev)		((dev)>>8)
+#define MINOR(dev)		((dev) & 0xff)
+
+#define _LINUX_CAPABILITY_VERSION_3	0x20080522
+#define _LINUX_CAPABILITY_U32S_3	2
+
+
+typedef struct {
+	unsigned long sig[2];
+} rt_sigset_t;
+
+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;
+
+typedef struct {
+	rt_sighandler_t	rt_sa_handler;
+	unsigned long	rt_sa_flags;
+	rt_sigrestore_t	rt_sa_restorer;
+	rt_sigset_t	rt_sa_mask;
+} rt_sigaction_t;
+
+#define _KNSIG		64
+#define _NSIG_BPW	32
+
+#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;
+}
+
+
+/*
+ * Copied from the Linux kernel header arch/arm/include/asm/ptrace.h
+ *
+ * A thread ARM CPU context
+ */
+
+typedef struct {
+        long uregs[18];
+} user_regs_struct_t;
+
+#define ARM_cpsr        uregs[16]
+#define ARM_pc          uregs[15]
+#define ARM_lr          uregs[14]
+#define ARM_sp          uregs[13]
+#define ARM_ip          uregs[12]
+#define ARM_fp          uregs[11]
+#define ARM_r10         uregs[10]
+#define ARM_r9          uregs[9]
+#define ARM_r8          uregs[8]
+#define ARM_r7          uregs[7]
+#define ARM_r6          uregs[6]
+#define ARM_r5          uregs[5]
+#define ARM_r4          uregs[4]
+#define ARM_r3          uregs[3]
+#define ARM_r2          uregs[2]
+#define ARM_r1          uregs[1]
+#define ARM_r0          uregs[0]
+#define ARM_ORIG_r0     uregs[17]
+
+
+/* Copied from arch/arm/include/asm/user.h */
+
+struct user_vfp {
+	unsigned long long fpregs[32];
+	unsigned long fpscr;
+};
+
+struct user_vfp_exc {
+        unsigned long   fpexc;
+	unsigned long   fpinst;
+	unsigned long   fpinst2;
+};
+
+#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)
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE	4096
+#endif
+
+#ifndef PAGE_MASK
+# define PAGE_MASK	(~(PAGE_SIZE - 1))
+#endif
+
+/* For sys_kcmp */
+enum kcmp_type {
+	KCMP_FILE,
+	KCMP_VM,
+	KCMP_FILES,
+	KCMP_FS,
+	KCMP_SIGHAND,
+	KCMP_IO,
+	KCMP_SYSVSEM,
+
+	KCMP_TYPES,
+};
+
+/* For UNIX sockets data */
+#ifndef SCM_MAX_FD
+# define SCM_MAX_FD	253
+#endif
+
+#include <fcntl.h>
+
+#ifndef F_SETOWN_EX
+#define F_SETOWN_EX	15
+#define F_GETOWN_EX	16
+
+struct f_owner_ex {
+	int	type;
+	pid_t	pid;
+};
+#endif
+
+/* File handle */
+typedef struct {
+	u32 bytes;
+	u32 type;
+	u64 __handle[16];
+} fh_t;
+
+#ifndef MAP_HUGETLB
+# define MAP_HUGETLB 0x40000
+#endif
+
+#ifndef MADV_HUGEPAGE
+# define MADV_HUGEPAGE 14
+#endif
+
+#ifndef MADV_NOHUGEPAGE
+# define MADV_NOHUGEPAGE 15
+#endif
+
+#ifndef MADV_DONTDUMP
+# define MADV_DONTDUMP 16
+#endif
+
+#define REG_RES(regs) ((regs).ARM_r0)
+#define REG_IP(regs)  ((regs).ARM_pc)
+
+#define TASK_SIZE 0xbf000000
+
+#define AT_VECTOR_SIZE 40
+
+typedef UserArmRegsEntry UserRegsEntry;
+
+#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__ARM
+
+#define CORE_THREAD_ARCH_INFO(core) core->ti_arm
+
+#define TI_SP(core) ((core)->ti_arm->gpregs->sp)
+
+typedef uint32_t auxv_t;
+
+static inline void *decode_pointer(uint64_t v) { return (void*)(uint32_t)v; }
+static inline uint64_t encode_pointer(void *p) { return (uint32_t)p; }
+
+#define BITS_PER_ULONG 32
+
+typedef struct {
+	struct user_vfp		ufp;
+	struct user_vfp_exc	ufp_exc;
+} fpu_state_t;
+
+#endif /* __CR_ASM_TYPES_H__ */
diff --git a/arch/arm/parasite-head.S b/arch/arm/parasite-head.S
new file mode 100644
index 0000000..b4bffe6
--- /dev/null
+++ b/arch/arm/parasite-head.S
@@ -0,0 +1,24 @@
+#include "asm/linkage.h"
+#include "parasite.h"
+
+	.section .head.text, "ax"
+ENTRY(__export_parasite_head_start)
+	adr	%sp, __export_parasite_stack
+        adr     %r0, __export_parasite_cmd
+	ldr	%r0, [%r0]
+        adr     %r1, __export_parasite_args
+	bl	parasite_service
+        .byte   0xf0, 0x01, 0xf0, 0xe7          @ the instruction UDF #32 generates the signal SIGTRAP in Linux
+
+__export_parasite_cmd:
+	.long 0
+__export_parasite_args:
+	.long 0
+	.space PARASITE_ARG_SIZE,0
+	.space PARASITE_STACK_SIZE,0
+
+        .space 228, 0
+
+__export_parasite_stack:
+	.long 0
+END(__export_parasite_head_start)
diff --git a/arch/arm/restorer.c b/arch/arm/restorer.c
new file mode 100644
index 0000000..bcef36c
--- /dev/null
+++ b/arch/arm/restorer.c
@@ -0,0 +1,50 @@
+#include <unistd.h>
+
+#include "restorer.h"
+#include "asm/restorer.h"
+#include "asm/memcpy_64.h"
+
+#include "syscall.h"
+#include "log.h"
+#include "fpu.h"
+#include "cpu.h"
+
+int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r)
+{
+#define CPREG1(d)       f->sig.uc.uc_mcontext.arm_##d = r->d
+#define CPREG2(d, s)    f->sig.uc.uc_mcontext.arm_##d = r->s
+
+	CPREG1(r0);
+	CPREG1(r1);
+	CPREG1(r2);
+	CPREG1(r3);
+	CPREG1(r4);
+	CPREG1(r5);
+	CPREG1(r6);
+	CPREG1(r7);
+	CPREG1(r8);
+	CPREG1(r9);
+	CPREG1(r10);
+	CPREG1(fp);
+	CPREG1(ip);
+	CPREG1(sp);
+	CPREG1(lr);
+	CPREG1(pc);
+	CPREG1(cpsr);
+
+#undef CPREG1
+#undef CPREG2
+
+	return 0;
+}
+
+int restore_fpu(struct rt_sigframe *sigframe, struct thread_restore_args *args)
+{
+	struct aux_sigframe *aux = (struct aux_sigframe *)&sigframe->sig.uc.uc_regspace;
+
+	aux->vfp.magic = VFP_MAGIC;
+	aux->vfp.size = VFP_STORAGE_SIZE;
+	builtin_memcpy(&aux->vfp.ufp, &args->fpu_state.ufp, sizeof(aux->vfp.ufp));
+
+	return 0;
+}
diff --git a/arch/arm/syscall-common.S b/arch/arm/syscall-common.S
new file mode 100644
index 0000000..d5dd18b
--- /dev/null
+++ b/arch/arm/syscall-common.S
@@ -0,0 +1,52 @@
+#include "asm/linkage.h"
+
+        .macro mov_r7 imm
+        mov %r7, #\imm
+        .endm
+
+
+        // Call the kernel
+
+        .macro do_sys opcode
+        movw    %r7, #\opcode
+        svc     #0
+        .endm
+
+
+        // a syscall with 0-4 arguments
+
+        .macro syscall0 name, opcode
+        ENTRY(\name)
+        push    { %r7 }
+        do_sys  \opcode
+        pop     { %r7 }
+        bx      %lr
+        END(\name)
+        .endm
+
+
+        // a syscall with 5 arguments
+
+        .macro syscall5 name, opcode
+        ENTRY(\name)
+        push    { %r4, %r7 }
+        ldr     %r4, [%sp, #8]
+        do_sys  \opcode
+        pop     { %r4, %r7 }
+        bx      %lr
+        END(\name)
+        .endm
+
+
+        // a syscall with 6 arguments
+
+        .macro syscall6 name, opcode
+        ENTRY(\name)
+        push    { %r4, %r5, %r7 }
+        ldr     %r4, [%sp, #12]
+        ldr     %r5, [%sp, #16]
+        do_sys  \opcode
+        pop     { %r4, %r5, %r7 }
+        bx      %lr
+        END(\name)
+        .endm
diff --git a/arch/arm/syscall.def b/arch/arm/syscall.def
new file mode 100644
index 0000000..ce175f3
--- /dev/null
+++ b/arch/arm/syscall.def
@@ -0,0 +1,78 @@
+#
+# System calls table, please make sure the table consist only the syscalls
+# really used somewhere in project.
+#
+# The template is (name and arguments are optinal if you need only __NR_x
+# defined, but no realy entry point in syscalls lib).
+#
+# name/alias			code	code32	arguments
+# -----------------------------------------------------------------------
+#
+read				0	3	(int fd, void *buf, unsigned long count)
+write				1	4	(int fd, const void *buf, unsigned long count)
+open				2	5	(const char *filename, unsigned long flags, unsigned long mode)
+close				3	6	(int fd)
+lseek				8	19	(int fd, unsigned long offset, unsigned long origin)
+mmap				9	!	(void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset)
+mprotect			10	125	(const void *addr, unsigned long len, unsigned long prot)
+munmap				11	91	(void *addr, unsigned long len)
+brk				12	45	(void *addr)
+rt_sigaction	sigaction	13	174	(int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize)
+rt_sigprocmask	sigprocmask	14	175	(int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize)
+rt_sigreturn			15	173	(void)
+mincore				27	219	(void *addr, unsigned long size, unsigned char *vec)
+ioctl				16	54	(unsigned int fd, unsigned int cmd, unsigned long arg)
+mremap				25	163	(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flag, unsigned long new_addr)
+madvise				28	220	(unsigned long start, size_t len, int behavior)
+shmat				30	305	(int shmid, void *shmaddr, int shmflag)
+pause				34	29	(void)
+nanosleep			35	162	(struct timespec *req, struct timespec *rem)
+getitimer			36	105	(int which, const struct itimerval *val)
+setitimer			38	104	(int which, const struct itimerval *val, struct itimerval *old)
+getpid				39	20	(void)
+socket				41	281	(int domain, int type, int protocol)
+connect				42	283	(int sockfd, struct sockaddr *addr, int addrlen)
+sendmsg				46	296	(int sockfd, const struct msghdr *msg, int flags)
+recvmsg				47	297	(int sockfd, struct msghdr *msg, int flags)
+bind				49	282	(int sockfd, const struct sockaddr *addr, int addrlen)
+setsockopt			54	294	(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
+getsockopt			55	295	(int sockfd, int level, int optname, const void *optval, socklen_t *optlen)
+clone				56	120	(unsigned long flags, void *child_stack, void *parent_tid, void *child_tid)
+exit				60	1	(unsigned long error_code)
+wait4				61	114	(int pid, int *status, int options, struct rusage *ru)
+kill				62	37	(long pid, int sig)
+fcntl				72	55	(int fd, int type, long arg)
+flock				73	143	(int fd, unsigned long cmd)
+mkdir				83	39	(const char *name, int mode)
+rmdir				84	40	(const char *name)
+unlink				87	10	(char *pathname)
+readlink			89	85	(const char *path, char *buf, int bufsize)
+umask				95	60	(int mask)
+getgroups			115	205	(int gsize, unsigned int *groups)
+setresuid			117	164	(int uid, int euid, int suid)
+setresgid			119	170	(int gid, int egid, int sgid)
+getpgid				121	132	(pid_t pid)
+setfsuid			122	138	(int fsuid)
+setfsgid			123	139	(int fsgid)
+getsid				124	147	(void)
+capset				126	185	(struct cap_header *h, struct cap_data *d)
+setpriority			141	97	(int which, int who, int nice)
+sched_setscheduler		144	156	(int pid, int policy, struct sched_param *p)
+personality			135	136	(unsigned int personality)
+prctl				157	172	(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
+arch_prctl			158	17	(int option, unsigned long addr)
+setrlimit			160	75	(int resource, struct krlimit *rlim)
+mount				165	21	(char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data)
+umount2				166	52	(char *name, int flags)
+gettid				186	224	(void)
+futex				202	240	(u32 *uaddr, int op, u32 val, struct timespec *utime, u32 *uaddr2, u32 val3)
+set_tid_address			218	256	(int *tid_addr)
+restart_syscall			219	0	(void)
+exit_group			231	248	(int error_code)
+set_robust_list			273	338	(struct robust_list_head *head, size_t len)
+get_robust_list			274	339	(int pid, struct robust_list_head **head_ptr, size_t *len_ptr)
+fanotify_init			300	367	(unsigned int flags, unsigned int event_f_flags)
+fanotify_mark			301	368	(int fanotify_fd, unsigned int flags, u64 mask, int dfd, const char *pathname)
+open_by_handle_at		304	371	(int mountdirfd, struct file_handle *handle, int flags)
+setns				308	375	(int fd, int nstype)
+kcmp				312	378	(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2)
diff --git a/arch/arm/uidiv.S b/arch/arm/uidiv.S
new file mode 100644
index 0000000..e77f610
--- /dev/null
+++ b/arch/arm/uidiv.S
@@ -0,0 +1,186 @@
+.globl __aeabi_uidiv
+
+work		.req	r4	@ XXXX is this safe ?
+dividend	.req	r0
+divisor		.req	r1
+overdone	.req	r2
+result		.req	r2
+curbit		.req	r3
+
+#define	LSYM(x) x
+
+.macro THUMB_DIV_MOD_BODY modulo
+	@ Load the constant 0x10000000 into our work register.
+	mov	work, #1
+	lsl	work, #28
+LSYM(Loop1):
+	@ Unless the divisor is very big, shift it up in multiples of
+	@ four bits, since this is the amount of unwinding in the main
+	@ division loop.  Continue shifting until the divisor is
+	@ larger than the dividend.
+	cmp	divisor, work
+	bhs	LSYM(Lbignum)
+	cmp	divisor, dividend
+	bhs	LSYM(Lbignum)
+	lsl	divisor, #4
+	lsl	curbit,  #4
+	b	LSYM(Loop1)
+LSYM(Lbignum):
+	@ Set work to 0x80000000
+	lsl	work, #3
+LSYM(Loop2):
+	@ For very big divisors, we must shift it a bit at a time, or
+	@ we will be in danger of overflowing.
+	cmp	divisor, work
+	bhs	LSYM(Loop3)
+	cmp	divisor, dividend
+	bhs	LSYM(Loop3)
+	lsl	divisor, #1
+	lsl	curbit,  #1
+	b	LSYM(Loop2)
+LSYM(Loop3):
+	@ Test for possible subtractions ...
+  .if \modulo
+	@ ... On the final pass, this may subtract too much from the dividend,
+	@ so keep track of which subtractions are done, we can fix them up
+	@ afterwards.
+	mov	overdone, #0
+	cmp	dividend, divisor
+	blo	LSYM(Lover1)
+	sub	dividend, dividend, divisor
+LSYM(Lover1):
+	lsr	work, divisor, #1
+	cmp	dividend, work
+	blo	LSYM(Lover2)
+	sub	dividend, dividend, work
+	mov	ip, curbit
+	mov	work, #1
+	ror	curbit, work
+	orr	overdone, curbit
+	mov	curbit, ip
+LSYM(Lover2):
+	lsr	work, divisor, #2
+	cmp	dividend, work
+	blo	LSYM(Lover3)
+	sub	dividend, dividend, work
+	mov	ip, curbit
+	mov	work, #2
+	ror	curbit, work
+	orr	overdone, curbit
+	mov	curbit, ip
+LSYM(Lover3):
+	lsr	work, divisor, #3
+	cmp	dividend, work
+	blo	LSYM(Lover4)
+	sub	dividend, dividend, work
+	mov	ip, curbit
+	mov	work, #3
+	ror	curbit, work
+	orr	overdone, curbit
+	mov	curbit, ip
+LSYM(Lover4):
+	mov	ip, curbit
+  .else
+	@ ... and note which bits are done in the result.  On the final pass,
+	@ this may subtract too much from the dividend, but the result will be ok,
+	@ since the "bit" will have been shifted out at the bottom.
+	cmp	dividend, divisor
+	blo	LSYM(Lover1)
+	sub	dividend, dividend, divisor
+	orr	result, result, curbit
+LSYM(Lover1):
+	lsr	work, divisor, #1
+	cmp	dividend, work
+	blo	LSYM(Lover2)
+	sub	dividend, dividend, work
+	lsr	work, curbit, #1
+	orr	result, work
+LSYM(Lover2):
+	lsr	work, divisor, #2
+	cmp	dividend, work
+	blo	LSYM(Lover3)
+	sub	dividend, dividend, work
+	lsr	work, curbit, #2
+	orr	result, work
+LSYM(Lover3):
+	lsr	work, divisor, #3
+	cmp	dividend, work
+	blo	LSYM(Lover4)
+	sub	dividend, dividend, work
+	lsr	work, curbit, #3
+	orr	result, work
+LSYM(Lover4):
+  .endif
+
+	cmp	dividend, #0			@ Early termination?
+	beq	LSYM(Lover5)
+	lsr	curbit,  #4			@ No, any more bits to do?
+	beq	LSYM(Lover5)
+	lsr	divisor, #4
+	b	LSYM(Loop3)
+LSYM(Lover5):
+  .if \modulo
+	@ Any subtractions that we should not have done will be recorded in
+	@ the top three bits of "overdone".  Exactly which were not needed
+	@ are governed by the position of the bit, stored in ip.
+	mov	work, #0xe
+	lsl	work, #28
+	and	overdone, work
+	beq	LSYM(Lgot_result)
+
+	@ If we terminated early, because dividend became zero, then the
+	@ bit in ip will not be in the bottom nibble, and we should not
+	@ perform the additions below.  We must test for this though
+	@ (rather relying upon the TSTs to prevent the additions) since
+	@ the bit in ip could be in the top two bits which might then match
+	@ with one of the smaller RORs.
+	mov	curbit, ip
+	mov	work, #0x7
+	tst	curbit, work
+	beq	LSYM(Lgot_result)
+
+	mov	curbit, ip
+	mov	work, #3
+	ror	curbit, work
+	tst	overdone, curbit
+	beq	LSYM(Lover6)
+	lsr	work, divisor, #3
+	add	dividend, work
+LSYM(Lover6):
+	mov	curbit, ip
+	mov	work, #2
+	ror	curbit, work
+	tst	overdone, curbit
+	beq	LSYM(Lover7)
+	lsr	work, divisor, #2
+	add	dividend, work
+LSYM(Lover7):
+	mov	curbit, ip
+	mov	work, #1
+	ror	curbit, work
+	tst	overdone, curbit
+	beq	LSYM(Lgot_result)
+	lsr	work, divisor, #1
+	add	dividend, work
+  .endif
+LSYM(Lgot_result):
+.endm
+
+
+	.thumb
+	.text
+
+__aeabi_uidiv:
+	mov	curbit, #1
+	mov	result, #0
+
+	push	{ work }
+	cmp	dividend, divisor
+	blo	LSYM(Lgot_result)
+
+	THUMB_DIV_MOD_BODY 0
+
+	mov	r0, result
+	pop	{ work }
+
+	bx      lr
diff --git a/test/zdtm/lib/arch/arm/include/asm/atomic.h b/test/zdtm/lib/arch/arm/include/asm/atomic.h
new file mode 100644
index 0000000..6d91ceb
--- /dev/null
+++ b/test/zdtm/lib/arch/arm/include/asm/atomic.h
@@ -0,0 +1,66 @@
+#ifndef __CR_ATOMIC_H__
+#define __CR_ATOMIC_H__
+
+
+typedef uint32_t atomic_t;
+
+
+/* Copied from the Linux kernel header arch/arm/include/asm/atomic.h */
+
+#define smp_mb() __asm__ __volatile__ ("dmb" : : : "memory")
+
+#define atomic_set(mem,v) (*(mem) = (v))
+#define atomic_get(v) (*(volatile uint32_t *)v)
+
+static inline unsigned int atomic_add_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	unsigned int result;
+
+	smp_mb();
+
+	__asm__ __volatile__("@ atomic_add_return\n"
+"1:	ldrex	%0, [%3]\n"
+"	add	%0, %0, %4\n"
+"	strex	%1, %0, [%3]\n"
+"	teq	%1, #0\n"
+"	bne	1b\n"
+	: "=&r" (result), "=&r" (tmp), "+Qo" (v)
+        : "r" (&v), "Ir" (i)
+	: "cc");
+
+	smp_mb();
+
+	return result;
+}
+
+static inline unsigned int atomic_sub_return(int i, atomic_t *v)
+{
+	unsigned long tmp;
+	int result;
+
+	smp_mb();
+
+	__asm__ __volatile__("@ atomic_sub_return\n"
+"1:	ldrex	%0, [%3]\n"
+"	sub	%0, %0, %4\n"
+"	strex	%1, %0, [%3]\n"
+"	teq	%1, #0\n"
+"	bne	1b\n"
+	: "=&r" (result), "=&r" (tmp), "+Qo" (v)
+	: "r" (&v), "Ir" (i)
+	: "cc");
+
+	smp_mb();
+
+	return result;
+}
+
+static inline unsigned int atomic_inc(atomic_t *v) { return atomic_add_return(1, v) - 1; }
+
+static inline unsigned 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)
+
+#endif /* __CR_ATOMIC_H__ */
-- 
1.7.10.4



More information about the CRIU mailing list