[CRIU] [PATCH 3/3] ARM: added ARM-specific files modelled after arch/x86
Alexander Kartashov
alekskartashov at parallels.com
Mon Jan 14 02:37:22 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 | 149 +++++++++++++++++++
arch/arm/include/asm/syscall-aux.S | 9 ++
arch/arm/include/asm/syscall-aux.h | 8 +
arch/arm/include/asm/types.h | 245 +++++++++++++++++++++++++++++++
arch/arm/parasite-head.S | 24 +++
arch/arm/restorer.c | 64 ++++++++
arch/arm/syscall-common.S | 52 +++++++
arch/arm/syscall.def | 76 ++++++++++
arch/arm/uidiv.S | 186 +++++++++++++++++++++++
23 files changed, 1601 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
diff --git a/Makefile b/Makefile
index 1c9b12c..f8e8c2e 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..af11f47
--- /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, ®s);
+ err = __parasite_execute(ctl, ctl->pid, ®s);
+ 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, ®s)) {
+ 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_INFO(core)->fpstate->vfp_regs, &vfp.fpregs, sizeof(vfp.fpregs));
+ CORE_THREAD_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_INFO(core)) {
+ if (CORE_THREAD_INFO(core)->fpstate) {
+ xfree(CORE_THREAD_INFO(core)->fpstate->vfp_regs);
+ xfree(CORE_THREAD_INFO(core)->fpstate);
+ }
+ xfree(CORE_THREAD_INFO(core)->gpregs);
+ }
+ xfree(CORE_THREAD_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_INFO(core)->fpstate->vfp_regs,
+ sizeof(args->fpu_state.ufp.fpregs));
+ args->fpu_state.ufp.fpscr = CORE_THREAD_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..c6267f4
--- /dev/null
+++ b/arch/arm/include/asm/restorer.h
@@ -0,0 +1,149 @@
+#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"
+ );
+}
+
+int arch_setrlimit(int resource, struct rlimit *rlim);
+
+#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..17fe887
--- /dev/null
+++ b/arch/arm/include/asm/types.h
@@ -0,0 +1,245 @@
+#ifndef __CR_ASM_TYPES_H__
+#define __CR_ASM_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <signal.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
+
+#define UserRegsEntry UserArmRegsEntry
+
+#define CORE_ENTRY__MARCH CORE_ENTRY__MARCH__ARM
+
+#define CORE_THREAD_INFO(core) core->ti_arm
+
+#define TI_SP(core) ((core)->ti_arm->gpregs->sp)
+
+typedef uint32_t auxv_t;
+
+#define P(i) ((unsigned long int)i)
+
+
+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..7bcc2a1
--- /dev/null
+++ b/arch/arm/restorer.c
@@ -0,0 +1,64 @@
+#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;
+}
+
+struct krlimit {
+ unsigned long rlim_cur;
+ unsigned long rlim_max;
+};
+
+int arch_setrlimit(int resource, struct rlimit *rlim)
+{
+ struct krlimit krlim;
+
+ krlim.rlim_cur = rlim->rlim_cur;
+ krlim.rlim_max = rlim->rlim_max;
+ return sys_setrlimit(resource, &krlim);
+}
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..569b0b2
--- /dev/null
+++ b/arch/arm/syscall.def
@@ -0,0 +1,76 @@
+#
+# 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)
+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
--
1.7.10.4
More information about the CRIU
mailing list