[RFC,v2,34/37] lkl: Android ARM (arm/arm64) support
diff mbox series

Message ID ec1915b36d1e4de138bfad60862beaaef0b47274.1573179553.git.thehajime@gmail.com
State Under Review
Delegated to: Richard Weinberger
Headers show
Series
  • [RFC,v2,01/37] asm-generic: atomic64: allow using generic atomic64 on 64bit platforms
Related show

Commit Message

Hajime Tazaki Nov. 8, 2019, 5:02 a.m. UTC
Initial attempt to run an application with hijack library on Android
platform.  Tested mostly on Android 6.x and 7.x.

The build process assumes that the android ndk toolchain is installed in
a host system. arm32 build is required to use alternate linker in order
to avoid a link issue during the build (described in *1).

*1
https://github.com/lkl/linux/issues/59#issuecomment-308961122

Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 arch/um/lkl/Kconfig            |  1 +
 tools/lkl/Makefile.autoconf    |  7 +++-
 tools/lkl/lib/hijack/hijack.c  | 13 ++++++++
 tools/lkl/lib/hijack/init.c    | 11 ++++++
 tools/lkl/tests/disk.sh        | 11 +++++-
 tools/lkl/tests/hijack-test.sh | 43 ++++++++++++++++++------
 tools/lkl/tests/test.sh        | 61 +++++++++++++++++++++++++++++++++-
 7 files changed, 134 insertions(+), 13 deletions(-)

Patch
diff mbox series

diff --git a/arch/um/lkl/Kconfig b/arch/um/lkl/Kconfig
index 1629e2679b75..fc501b64a2af 100644
--- a/arch/um/lkl/Kconfig
+++ b/arch/um/lkl/Kconfig
@@ -23,6 +23,7 @@  config LKL
        select 64BIT if "$(OUTPUT_FORMAT)" = "pe-x86-64"
        select HAVE_UNDERSCORE_SYMBOL_PREFIX if "$(OUTPUT_FORMAT)" = "pe-i386"
        select 64BIT if "$(OUTPUT_FORMAT)" = "elf64-x86-64-freebsd"
+       select 64BIT if "$(OUTPUT_FORMAT)" = "elf64-littleaarch64"
        select NET
        select MULTIUSER
        select INET
diff --git a/tools/lkl/Makefile.autoconf b/tools/lkl/Makefile.autoconf
index 1631f5cc25ac..7222a95c314f 100644
--- a/tools/lkl/Makefile.autoconf
+++ b/tools/lkl/Makefile.autoconf
@@ -1,4 +1,4 @@ 
-POSIX_HOSTS=elf64-x86-64 elf32-i386 elf64-x86-64-freebsd
+POSIX_HOSTS=elf64-x86-64 elf32-i386 elf64-x86-64-freebsd elf32-littlearm elf64-littleaarch64
 NT_HOSTS=pe-i386 pe-x86-64
 
 define set_autoconf_var
@@ -17,6 +17,10 @@  define is_defined
 $(shell $(CC) -dM -E - </dev/null | grep $(1))
 endef
 
+define android_host
+  $(call set_autoconf_var,ANDROID,y)
+endef
+
 define bsd_host
   $(call set_autoconf_var,BSD,y)
 endef
@@ -54,6 +58,7 @@  define posix_host
   LDFLAGS += -pie
   CFLAGS += -fPIC -pthread
   SOSUF := .so
+  $(if $(call is_defined,__ANDROID__),$(call android_host),LDLIBS += -lrt -lpthread)
   $(if $(filter $(1),elf64-x86-64-freebsd),$(call bsd_host))
   $(if $(filter $(1),elf32-littlearm),$(call arm_host))
   $(if $(filter $(1),elf64-littleaarch64),$(call aarch64_host))
diff --git a/tools/lkl/lib/hijack/hijack.c b/tools/lkl/lib/hijack/hijack.c
index 485c15d7c279..3a95b9dbe88b 100644
--- a/tools/lkl/lib/hijack/hijack.c
+++ b/tools/lkl/lib/hijack/hijack.c
@@ -204,7 +204,11 @@  int socket(int domain, int type, int protocol)
 }
 
 HOST_CALL(ioctl);
+#ifdef __ANDROID__
+int ioctl(int fd, int req, ...)
+#else
 int ioctl(int fd, unsigned long req, ...)
+#endif
 {
 	va_list vl;
 	long arg;
@@ -586,6 +590,15 @@  void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
 	return lkl_sys_mmap(addr, length, prot, flags, fd, offset);
 }
 
+#ifndef __ANDROID__
+HOST_CALL(__xstat64)
+int stat(const char *pathname, struct stat *buf)
+{
+	CHECK_HOST_CALL(__xstat64);
+	return host___xstat64(0, pathname, buf);
+}
+#endif
+
 ssize_t send(int fd, const void *buf, size_t len, int flags)
 {
 	return sendto(fd, buf, len, flags, 0, 0);
diff --git a/tools/lkl/lib/hijack/init.c b/tools/lkl/lib/hijack/init.c
index 2145fb7ec2cb..de00f2018e59 100644
--- a/tools/lkl/lib/hijack/init.c
+++ b/tools/lkl/lib/hijack/init.c
@@ -170,6 +170,17 @@  hijack_init(void)
 	if (single_cpu_mode == 1)
 		PinToFirstCpu(&ori_cpu);
 
+#ifdef __ANDROID__
+	struct sigaction sa;
+
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = 0;
+	if (sigaction(32, &sa, 0) == -1) {
+		perror("sigaction");
+		exit(1);
+	}
+#endif
+
 	ret = lkl_start_kernel(&lkl_host_ops, cfg->boot_cmdline);
 	if (ret) {
 		fprintf(stderr, "can't start kernel: %s\n", lkl_strerror(ret));
diff --git a/tools/lkl/tests/disk.sh b/tools/lkl/tests/disk.sh
index 9bdcb16f2d5c..e2ec6cf69d4b 100755
--- a/tools/lkl/tests/disk.sh
+++ b/tools/lkl/tests/disk.sh
@@ -15,6 +15,12 @@  function prepfs()
 
     yes | mkfs.$1 $file
 
+    if ! [ -z $ANDROID_WDIR ]; then
+        adb shell mkdir -p $ANDROID_WDIR
+        adb push $file $ANDROID_WDIR
+        rm $file
+        file=$ANDROID_WDIR/$(basename $file)
+    fi
     if ! [ -z $BSD_WDIR ]; then
         $MYSSH mkdir -p $BSD_WDIR
         ssh_copy $file $BSD_WDIR
@@ -29,7 +35,10 @@  function cleanfs()
 {
     set -e
 
-    if ! [ -z $BSD_WDIR ]; then
+    if ! [ -z $ANDROID_WDIR ]; then
+        adb shell rm $1
+        adb shell rm $ANDROID_WDIR/disk
+    elif ! [ -z $BSD_WDIR ]; then
         $MYSSH rm $1
         $MYSSH rm $BSD_WDIR/disk
     else
diff --git a/tools/lkl/tests/hijack-test.sh b/tools/lkl/tests/hijack-test.sh
index 097af6cff3ba..a62aa5b251e0 100755
--- a/tools/lkl/tests/hijack-test.sh
+++ b/tools/lkl/tests/hijack-test.sh
@@ -15,7 +15,11 @@  set_cfgjson()
 {
     cfgjson=${wdir}/hijack-test$1.conf
 
-    cat > ${cfgjson}
+    if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+        adb shell cat \> ${cfgjson}
+    else
+        cat > ${cfgjson}
+    fi
 
     export_vars cfgjson
 }
@@ -54,6 +58,11 @@  test_mount_and_dump()
 {
     set -e
 
+    if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+        echo "TODO: android-23 doesn't call destructor..."
+        return $TEST_SKIP
+    fi
+
     set_cfgjson << EOF
     {
         "mount":"proc,sysfs",
@@ -377,6 +386,10 @@  test_tap_qdisc()
 {
     set -e
 
+    if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+        return $TEST_SKIP
+    fi
+
     set_cfgjson << EOF
     {
         "gateway":"$(ip_host)",
@@ -655,15 +668,25 @@  if [[ ! -e ${basedir}/lib/hijack/liblkl-hijack.so ]]; then
     exit 0
 fi
 
-# Make a temporary directory to run tests in, since we'll be copying
-# things there.
-wdir=$(mktemp -d)
-cp `which ping` ${wdir}
-cp `which ping6` ${wdir}
-ping=${wdir}/ping
-ping6=${wdir}/ping6
-hijack=$basedir/bin/lkl-hijack.sh
-netperf=$basedir/tests/run_netperf.sh
+if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+    wdir=$ANDROID_WDIR
+    adb_push lib/hijack/liblkl-hijack.so bin/lkl-hijack.sh tests/net-setup.sh \
+             tests/run_netperf.sh tests/hijack-test.sh
+    ping="ping"
+    ping6="ping6"
+    hijack="$wdir/bin/lkl-hijack.sh"
+    netperf="$wdir/tests/run_netperf.sh"
+else
+    # Make a temporary directory to run tests in, since we'll be copying
+    # things there.
+    wdir=$(mktemp -d)
+    cp `which ping` ${wdir}
+    cp `which ping6` ${wdir}
+    ping=${wdir}/ping
+    ping6=${wdir}/ping6
+    hijack=$basedir/bin/lkl-hijack.sh
+    netperf=$basedir/tests/run_netperf.sh
+fi
 
 fifo1=${wdir}/fifo1
 fifo2=${wdir}/fifo2
diff --git a/tools/lkl/tests/test.sh b/tools/lkl/tests/test.sh
index cda932b98058..a40d08fd6185 100644
--- a/tools/lkl/tests/test.sh
+++ b/tools/lkl/tests/test.sh
@@ -100,6 +100,19 @@  lkl_test_exec()
 
     if file $file | grep PE32; then
         WRAPPER="wine"
+    elif file $file | grep "interpreter /system/bin/linker" ; then
+        adb push "$file" $ANDROID_WDIR
+        if [ -n "$SUDO" ]; then
+            ANDROID_USER=root
+            SUDO=""
+        fi
+        if [ -n "$ANDROID_USER" ]; then
+            SU="su $ANDROID_USER"
+        else
+            SU=""
+        fi
+        WRAPPER="adb shell $SU"
+        file=$ANDROID_WDIR/$(basename $file)
     elif file $file | grep ARM; then
         WRAPPER="qemu-arm-static"
     elif file $file | grep "FreeBSD" ; then
@@ -134,13 +147,48 @@  lkl_test_cmd()
         SHOPTS="-x"
     fi
 
-    if [ -n "$LKL_HOST_CONFIG_BSD" ]; then
+    if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+        if [ "$1" = "sudo" ]; then
+            ANDROID_USER=root
+            shift
+        fi
+        if [ -n "$ANDROID_USER" ]; then
+            SU="su $ANDROID_USER"
+        else
+            SU=""
+        fi
+        WRAPPER="adb shell $SU"
+    elif [ -n "$LKL_HOST_CONFIG_BSD" ]; then
         WRAPPER="$MYSSH $SU"
     fi
 
     echo "$@" | $WRAPPER sh $SHOPTS
 }
 
+adb_push()
+{
+    while [ -n "$1" ]; do
+        if [[ "$1" = *.sh ]]; then
+            type="script"
+        else
+            type="file"
+        fi
+
+        dir=$(dirname $1)
+        adb shell mkdir -p $ANDROID_WDIR/$dir
+
+        if [ "$type" = "script" ]; then
+            sed "s/\/usr\/bin\/env bash/\/system\/bin\/sh/" $basedir/$1 | \
+                adb shell cat \> $ANDROID_WDIR/$1
+            adb shell chmod a+x $ANDROID_WDIR/$1
+        else
+            adb push $basedir/$1 $ANDROID_WDIR/$dir
+        fi
+
+        shift
+    done
+}
+
 # XXX: $MYSSH and $MYSCP are defined in a circleci docker image.
 # see the definitions in lkl/lkl-docker:circleci/freebsd11/Dockerfile
 ssh_push()
@@ -169,11 +217,22 @@  ssh_copy()
     $MYSCP -P 7722 -r $1 root@localhost:$2
 }
 
+lkl_test_android_cleanup()
+{
+    adb shell rm -rf $ANDROID_WDIR
+}
+
 lkl_test_bsd_cleanup()
 {
     $MYSSH rm -rf $BSD_WDIR
 }
 
+if [ -n "$LKL_HOST_CONFIG_ANDROID" ]; then
+    trap lkl_test_android_cleanup EXIT
+    export ANDROID_WDIR=/data/local/tmp/lkl
+    adb shell mkdir -p $ANDROID_WDIR
+fi
+
 if [ -n "$LKL_HOST_CONFIG_BSD" ]; then
     trap lkl_test_bsd_cleanup EXIT
     export BSD_WDIR=/root/lkl