From 8a6ec661af2bb80504b1a37a9dae57de568a27af Mon Sep 17 00:00:00 2001
From: Claudio Fontana <claudio.fontana@huawei.com>
Date: Thu, 20 Mar 2014 13:20:14 +0100
Subject: [PATCH] libc: add minimal support for AArch64

this contains still prototyped code, which if reached either
hangs (setjmp, longjmp), aborts (all that requires mmu::),
or implements differently (allocating with malloc instead of mmap)
This is enough libc AArch64 support for reaching the end of premain.

Signed-off-by: Claudio Fontana <claudio.fontana@huawei.com>
---
 libc/arch/aarch64/atomic.h           | 38 ++++++++++++++++++++++++++++
 libc/arch/aarch64/setjmp/longjmp.s   | 14 ++++++++++
 libc/arch/aarch64/setjmp/setjmp.s    | 17 +++++++++++++
 libc/{ => arch/x64}/setjmp/longjmp.s |  0
 libc/{ => arch/x64}/setjmp/setjmp.s  |  0
 libc/build.mk                        |  4 +--
 libc/mman.cc                         | 28 ++++++++++++++++++++
 libc/pthread.cc                      | 13 ++++++++++
 libc/shm.cc                          | 12 +++++++++
 libc/string/memcpy.c                 | 10 ++++++++
 10 files changed, 134 insertions(+), 2 deletions(-)
 create mode 100644 libc/arch/aarch64/atomic.h
 create mode 100644 libc/arch/aarch64/setjmp/longjmp.s
 create mode 100644 libc/arch/aarch64/setjmp/setjmp.s
 rename libc/{ => arch/x64}/setjmp/longjmp.s (100%)
 rename libc/{ => arch/x64}/setjmp/setjmp.s (100%)

diff --git a/libc/arch/aarch64/atomic.h b/libc/arch/aarch64/atomic.h
new file mode 100644
index 000000000..fd997f9d4
--- /dev/null
+++ b/libc/arch/aarch64/atomic.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef _INTERNAL_ATOMIC_H
+#define _INTERNAL_ATOMIC_H
+
+#include <stdint.h>
+#include <bsd/sys/cddl/compat/opensolaris/sys/types.h>
+#include <machine/atomic.h>
+
+static inline int a_ctz_64(register uint64_t x)
+{
+	register uint64_t r;
+	__asm__ __volatile__ ("rbit %0, %0; clz %1, %0" : "+r"(x), "=r"(r));
+	return r;
+}
+
+static inline int a_ctz_l(unsigned long x)
+{
+	return a_ctz_64(x);
+}
+
+static inline int a_fetch_add(volatile int *x, int v)
+{
+    return atomic_fetchadd_int((unsigned int *)x, (unsigned int)v);
+}
+
+static inline void a_crash()
+{
+    __asm__ __volatile__( "1: msr daifset, #2; wfi; b 1b; " ::: "memory");
+}
+
+
+#endif /* _INTERNAL_ATOMIC_H */
diff --git a/libc/arch/aarch64/setjmp/longjmp.s b/libc/arch/aarch64/setjmp/longjmp.s
new file mode 100644
index 000000000..cf73028e4
--- /dev/null
+++ b/libc/arch/aarch64/setjmp/longjmp.s
@@ -0,0 +1,14 @@
+/* Copyright 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+.global _longjmp
+.global longjmp
+.type _longjmp,@function
+.type longjmp,@function
+_longjmp:
+longjmp:
+        wfi
+        b longjmp
diff --git a/libc/arch/aarch64/setjmp/setjmp.s b/libc/arch/aarch64/setjmp/setjmp.s
new file mode 100644
index 000000000..654ecb26a
--- /dev/null
+++ b/libc/arch/aarch64/setjmp/setjmp.s
@@ -0,0 +1,17 @@
+/* Copyright 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp,@function
+.type _setjmp,@function
+.type setjmp,@function
+__setjmp:
+_setjmp:
+setjmp:
+        wfi
+        b setjmp
diff --git a/libc/setjmp/longjmp.s b/libc/arch/x64/setjmp/longjmp.s
similarity index 100%
rename from libc/setjmp/longjmp.s
rename to libc/arch/x64/setjmp/longjmp.s
diff --git a/libc/setjmp/setjmp.s b/libc/arch/x64/setjmp/setjmp.s
similarity index 100%
rename from libc/setjmp/setjmp.s
rename to libc/arch/x64/setjmp/setjmp.s
diff --git a/libc/build.mk b/libc/build.mk
index 2f6f1af87..e906e4e76 100644
--- a/libc/build.mk
+++ b/libc/build.mk
@@ -380,8 +380,8 @@ libc += network/if_indextoname.o
 libc += prng/rand.o
 libc += prng/random.o
 
-libc += setjmp/setjmp.o
-libc += setjmp/longjmp.o
+libc += arch/$(arch)/setjmp/setjmp.o
+libc += arch/$(arch)/setjmp/longjmp.o
 
 libc += signal/sigrtmax.o
 libc += signal/sigrtmin.o
diff --git a/libc/mman.cc b/libc/mman.cc
index 8a9eed84e..59ef46dbd 100644
--- a/libc/mman.cc
+++ b/libc/mman.cc
@@ -57,6 +57,9 @@ unsigned libc_prot_to_perm(int prot)
 
 int mprotect(void *addr, size_t len, int prot)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     // we don't support mprotecting() the linear map (e.g.., malloc() memory)
     // because that could leave the linear map a mess.
     if (reinterpret_cast<long>(addr) < 0) {
@@ -70,10 +73,14 @@ int mprotect(void *addr, size_t len, int prot)
     }
 
     return mmu::mprotect(addr, len, libc_prot_to_perm(prot)).to_libc();
+#endif /* !AARCH64_PORT_STUB */
 }
 
 int mmap_validate(void *addr, size_t length, int flags, off_t offset)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     int type = flags & (MAP_SHARED|MAP_PRIVATE);
     // Either MAP_SHARED or MAP_PRIVATE must be set, but not both.
     if (!type || type == (MAP_SHARED|MAP_PRIVATE)) {
@@ -84,11 +91,15 @@ int mmap_validate(void *addr, size_t length, int flags, off_t offset)
         return EINVAL;
     }
     return 0;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 void *mmap(void *addr, size_t length, int prot, int flags,
            int fd, off_t offset)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     trace_memory_mmap(addr, length, prot, flags, fd, offset);
 
     int err = mmap_validate(addr, length, flags, offset);
@@ -125,6 +136,7 @@ void *mmap(void *addr, size_t length, int prot, int flags,
     }
     trace_memory_mmap_ret(ret);
     return ret;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 extern "C" void *mmap64(void *addr, size_t length, int prot, int flags,
@@ -134,14 +146,21 @@ extern "C" void *mmap64(void *addr, size_t length, int prot, int flags,
 
 int munmap_validate(void *addr, size_t length)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     if (!mmu::is_page_aligned(addr) || length == 0) {
         return EINVAL;
     }
     return 0;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 int munmap(void *addr, size_t length)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     trace_memory_munmap(addr, length);
     int error = munmap_validate(addr, length);
     if (error) {
@@ -155,18 +174,27 @@ int munmap(void *addr, size_t length)
     }
     trace_memory_munmap_ret();
     return ret;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 int msync(void *addr, size_t length, int flags)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     return mmu::msync(addr, length, flags).to_libc();
+#endif /* !AARCH64_PORT_STUB */
 }
 
 int mincore(void *addr, size_t length, unsigned char *vec)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     if (!mmu::is_page_aligned(addr)) {
         return libc_error(EINVAL);
     }
 
     return mmu::mincore(addr, length, vec).to_libc();
+#endif /* !AARCH64_PORT_STUB */
 }
diff --git a/libc/pthread.cc b/libc/pthread.cc
index 4e594b240..abfdabb2a 100644
--- a/libc/pthread.cc
+++ b/libc/pthread.cc
@@ -14,7 +14,11 @@
 #include <algorithm>
 #include <string.h>
 #include <list>
+
+#ifndef AARCH64_PORT_STUB
 #include <osv/mmu.hh>
+#endif /* !AARCH64_PORT_STUB */
+
 #include <osv/debug.hh>
 #include <osv/prio.hh>
 
@@ -90,8 +94,13 @@ namespace pthread_private {
             return {attr.stack_begin, attr.stack_size};
         }
         size_t size = attr.stack_size;
+#ifdef AARCH64_PORT_STUB
+        size = (size + (0xfff)) & (~0xfffull);
+        void *addr = malloc(size);
+#else  /* !AARCH64_PORT_STUB */
         void *addr = mmu::map_anon(nullptr, size, mmu::mmap_populate, mmu::perm_rw);
         mmu::mprotect(addr, attr.guard_size, 0);
+#endif /* !AARCH64_PORT_STUB */
         sched::thread::stack_info si{addr, size};
         si.deleter = free_stack;
         return si;
@@ -99,7 +108,11 @@ namespace pthread_private {
 
     void pthread::free_stack(sched::thread::stack_info si)
     {
+#ifdef AARCH64_PORT_STUB
+        free(si.begin);
+#else  /* !AARCH64_PORT_STUB */
         mmu::munmap(si.begin, si.size);
+#endif /* !AARCH64_PORT_STUB */
     }
 
     int pthread::join(void** retval)
diff --git a/libc/shm.cc b/libc/shm.cc
index a3c685521..c9cdc5b58 100644
--- a/libc/shm.cc
+++ b/libc/shm.cc
@@ -23,6 +23,9 @@ static std::unordered_map<const void*, int> shmmap;
 
 void *shmat(int shmid, const void *shmaddr, int shmflg)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     fileref f(fileref_from_fd(shmid));
     void *addr;
     try {
@@ -36,6 +39,7 @@ void *shmat(int shmid, const void *shmaddr, int shmflg)
         shmmap.emplace(addr, shmid);
     }
     return addr;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
@@ -49,6 +53,9 @@ int shmctl(int shmid, int cmd, struct shmid_ds *buf)
 
 int shmdt(const void *shmaddr)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else /* !AARCH64_PORT_STUB */
     int fd;
     WITH_LOCK(shm_lock) {
         auto s = shmmap.find(shmaddr);
@@ -61,6 +68,7 @@ int shmdt(const void *shmaddr)
     fileref f(fileref_from_fd(fd));
     mmu::munmap(shmaddr, ::size(f));
     return 0;
+#endif /* !AARCH64_PORT_STUB */
 }
 
 /*
@@ -69,6 +77,9 @@ int shmdt(const void *shmaddr)
  */
 int shmget(key_t key, size_t size, int shmflg)
 {
+#ifdef AARCH64_PORT_STUB
+    abort();
+#else
     int fd;
     int flags = FREAD | FWRITE;
     size = align_up(size, mmu::page_size);
@@ -96,4 +107,5 @@ int shmget(key_t key, size_t size, int shmflg)
         return libc_error(error);
     }
     return fd;
+#endif /* !AARCH64_PORT_STUB */
 }
diff --git a/libc/string/memcpy.c b/libc/string/memcpy.c
index 23162151f..49ea8fe36 100644
--- a/libc/string/memcpy.c
+++ b/libc/string/memcpy.c
@@ -27,3 +27,13 @@ misaligned:
 	}
 	return dest;
 }
+
+void *memcpy_base_backwards(void *__restrict dest, const void *__restrict src, size_t n)
+{
+	unsigned char *d = dest + n - 1;
+	const unsigned char *s = src + n - 1;
+
+	for (; n; n--) *d-- = *s--;
+
+	return dest;
+}
-- 
GitLab