diff --git a/Makefile b/Makefile
index 0a3ee69..a7da622 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,8 @@ export OBJDUMP  := $(KLIBCROSS)objdump
 
 NOSTDINC_FLAGS := -nostdlib -nostdinc -isystem $(shell $(CC) -print-file-name=include)
 
-ARCH	          := $(shell uname -m | sed -e s/i.86/i386/ -e s/parisc64/parisc/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/sh.*/sh/)
+ARCH	          := $(shell uname -m | sed -e s/i.86/i386/ -e s/parisc64/parisc/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ \
+			-e s/aarch64.*/arm64/ -e s/sh.*/sh/)
 export KLIBCARCH  ?= $(ARCH)
 export KLIBCARCHDIR := $(shell echo $(KLIBCARCH) | sed -e s/s390x/s390/)
 
diff --git a/usr/include/arch/arm64/klibc/archconfig.h b/usr/include/arch/arm64/klibc/archconfig.h
new file mode 100644
index 0000000..5e2004b
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archconfig.h
@@ -0,0 +1,17 @@
+/*
+ * include/arch/arm64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* Use rt_* signals */
+#define _KLIBC_USE_RT_SIG 1
+#define _KLIBC_NO_MMU 0
+#define _KLIBC_REAL_VFORK 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/arm64/klibc/archsetjmp.h b/usr/include/arch/arm64/klibc/archsetjmp.h
new file mode 100644
index 0000000..1738617
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archsetjmp.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+/*
+ * x19-x28 are callee saved, also save fp, lr, sp.
+ * d8-d15 are also callee saved.
+ */
+
+struct __jmp_buf {
+	uint64_t __gregs[13];
+	uint64_t __fpregs[8];
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/arm64/klibc/archsignal.h b/usr/include/arch/arm64/klibc/archsignal.h
new file mode 100644
index 0000000..94e6bc8
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/arm64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/arm64/klibc/archstat.h b/usr/include/arch/arm64/klibc/archstat.h
new file mode 100644
index 0000000..a1a3e79
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archstat.h
@@ -0,0 +1,29 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+struct stat {
+          unsigned long   st_dev;         /* Device.  */
+          unsigned long   st_ino;         /* File serial number.  */
+          unsigned int    st_mode;        /* File mode.  */
+          unsigned int    st_nlink;       /* Link count.  */
+          unsigned int    st_uid;         /* User ID of the file's owner.  */
+          unsigned int    st_gid;         /* Group ID of the file's group. */
+          unsigned long   st_rdev;        /* Device number, if device.  */
+          unsigned long   __pad1;
+          long            st_size;        /* Size of file, in bytes.  */
+          int             st_blksize;     /* Optimal block size for I/O.  */
+          int             __pad2;
+          long            st_blocks;      /* Number 512-byte blocks allocated. */
+          long            st_atime;       /* Time of last access.  */
+          unsigned long   st_atime_nsec;
+          long            st_mtime;       /* Time of last modification.  */
+          unsigned long   st_mtime_nsec;
+          long            st_ctime;       /* Time of last status change.  */
+          unsigned long   st_ctime_nsec;
+          unsigned int    __unused4;
+          unsigned int    __unused5;
+  };
+
+#endif
diff --git a/usr/include/arch/arm64/klibc/asmmacros.h b/usr/include/arch/arm64/klibc/asmmacros.h
new file mode 100644
index 0000000..c298f66
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/asmmacros.h
@@ -0,0 +1,11 @@
+/*
+ * usr/include/arch/arm64/klibc/asmmacros.h
+ *
+ * Assembly macros used by arm64 system call stubs
+ */
+
+#ifndef _KLIBC_ASMMACROS_H
+#define _KLIBC_ASMMACROS_H
+
+
+#endif /* _KLIBC_ASMMACROS_H */
diff --git a/usr/klibc/README.klibc b/usr/klibc/README.klibc
index 7de5fea..c72ae47 100644
--- a/usr/klibc/README.klibc
+++ b/usr/klibc/README.klibc
@@ -36,6 +36,7 @@ b) If you're cross-compiling, you need to set KLIBCARCH to the
    arm-thumb:	 Untested
    arm:		 Working
    arm26:	 Not yet ported
+   arm64:	 Working
    avr32:	 Not yet ported
    cris:	 Working
    h8300:	 Not yet ported
diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def
index c2f36e7..c1f5b70 100644
--- a/usr/klibc/SYSCALLS.def
+++ b/usr/klibc/SYSCALLS.def
@@ -21,7 +21,7 @@ void _exit,exit::_exit(int);
 <?!ia64> pid_t clone::__clone(unsigned long, void *);
 <?ia64> pid_t clone::__clone2(unsigned long, void *, void *);
 # if ! _KLIBC_NO_MMU
-<!sparc,sparc64,ia64> pid_t fork();
+<!sparc,sparc64,ia64,arm64> pid_t fork();
 <sparc,sparc64> pid_t fork@forkish();
 #endif
 #if _KLIBC_REAL_VFORK
@@ -124,7 +124,7 @@ int fchmod(int, mode_t);
 <?> int mkdir(const char *, mode_t);
 <?> int mkdirat(int, const char *, mode_t);
 <?> int rmdir(const char *);
-<!alpha,ia64,mips,mips64,sh,sparc,sparc64> int pipe(int *);
+<!alpha,arm64,ia64,mips,mips64,sh,sparc,sparc64> int pipe(int *);
 int pipe2(int *, int);
 mode_t umask(mode_t);
 int chroot(const char *);
@@ -132,8 +132,8 @@ int chroot(const char *);
 <?> int symlinkat(const char *, int, const char *);
 <?> int readlink(const char *, char *, size_t);
 <?> int readlinkat(int, const char *, char *, int);
-<!ppc64> int stat64,stat::stat(const char *, struct stat *);
-<!ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
+<!arm64,ppc64> int stat64,stat::stat(const char *, struct stat *);
+<!arm64,ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
 <!ppc64> int fstat64,fstat::fstat(int, struct stat *);
 <ppc64> int stat::stat(const char *, struct stat *);
 <ppc64> int lstat::lstat(const char *, struct stat *);
diff --git a/usr/klibc/arch/arm64/Kbuild b/usr/klibc/arch/arm64/Kbuild
new file mode 100644
index 0000000..c23bd69
--- /dev/null
+++ b/usr/klibc/arch/arm64/Kbuild
@@ -0,0 +1,7 @@
+
+# klibc files for arm64
+#
+
+klib-y := setjmp.o syscall.o vfork.o pipe.o
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/arm64/MCONFIG b/usr/klibc/arch/arm64/MCONFIG
new file mode 100644
index 0000000..dfebc5e
--- /dev/null
+++ b/usr/klibc/arch/arm64/MCONFIG
@@ -0,0 +1,23 @@
+# -*- makefile -*-
+#
+# arch/arm64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+CPU_ARCH ?= armv8-a
+CPU_TUNE ?= generic
+
+KLIBCOPTFLAGS += -g -Os -march=$(CPU_ARCH) -mtune=$(CPU_TUNE)
+KLIBCBITSIZE  = 64
+KLIBCREQFLAGS += -fno-exceptions
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+
+# On arm64, binaries are normally loaded at 4MB. Place klibc.so
+# a little before that at 2MB to prevent overlap.
+KLIBCSHAREDFLAGS = -Ttext 0x0200000
diff --git a/usr/klibc/arch/arm64/crt0.S b/usr/klibc/arch/arm64/crt0.S
new file mode 100644
index 0000000..0b2dd32
--- /dev/null
+++ b/usr/klibc/arch/arm64/crt0.S
@@ -0,0 +1,19 @@
+#
+# arch/arm64/crt0.S
+#
+# void _start(void)
+# {
+#    __libc_init(elf_structure, atexit_ptr);
+# }
+#
+
+	.text
+	.balign 8
+	.type _start,#function
+	.globl _start
+
+_start:
+	mov	x0, sp
+	mov	x1, #0
+	bl	__libc_init
+	.size _start,.-_start
diff --git a/usr/klibc/arch/arm64/pipe.c b/usr/klibc/arch/arm64/pipe.c
new file mode 100644
index 0000000..f10a69e
--- /dev/null
+++ b/usr/klibc/arch/arm64/pipe.c
@@ -0,0 +1,10 @@
+#include <unistd.h>
+
+#ifndef __NR_pipe
+
+int pipe(int pipefd[2])
+{
+	return pipe2(pipefd, 0);
+}
+
+#endif  /* __NR_pipe */
diff --git a/usr/klibc/arch/arm64/setjmp.S b/usr/klibc/arch/arm64/setjmp.S
new file mode 100644
index 0000000..3d5c1c6
--- /dev/null
+++ b/usr/klibc/arch/arm64/setjmp.S
@@ -0,0 +1,52 @@
+#
+# arch/arm64/setjmp.S
+#
+# setjmp/longjmp for arm64
+#
+
+#include <klibc/asmmacros.h>
+
+	.text
+	.balign 8
+	.globl setjmp
+	.type setjmp, #function
+setjmp:
+	mov	x1, sp
+	stp	x19, x20, [x0, #0]
+	stp	x21, x22, [x0, #16]
+	stp	x23, x24, [x0, #32]
+	stp	x25, x26, [x0, #48]
+	stp	x27, x28, [x0, #64]
+	stp	x29, x30, [x0, #80]
+	str	x1,       [x0, #96]
+	stp	d8, d9,   [x0, #104]
+	stp	d10, d11, [x0, #120]
+	stp	d12, d13, [x0, #136]
+	stp	d14, d15, [x0, #152]
+	mov	x0, #0 			/* set the return value of setjmp */
+	br	x30
+	.size setjmp,.-setjmp
+
+	.text
+	.balign 8
+	.globl longjmp
+	.type longjmp, #function
+longjmp:
+	ldp	x19, x20, [x0, #0]
+	ldp	x21, x22, [x0, #16]
+	ldp	x23, x24, [x0, #32]
+	ldp	x25, x26, [x0, #48]
+	ldp	x27, x28, [x0, #64]
+	ldp	x29, x30, [x0, #80]
+	ldr	x2,	  [x0, #96]
+	ldp	d8, d9,   [x0, #104]
+	ldp	d10, d11, [x0, #120]
+	ldp	d12, d13, [x0, #136]
+	ldp	d14, d15, [x0, #152]
+	mov	sp, x2
+	mov	x0, x1
+	cbnz	x1, 1f
+	mov	x0, #1
+1:
+	br	x30
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/arm64/syscall.S b/usr/klibc/arch/arm64/syscall.S
new file mode 100644
index 0000000..3ce91fb
--- /dev/null
+++ b/usr/klibc/arch/arm64/syscall.S
@@ -0,0 +1,25 @@
+/*
+ * arch/arm64/syscall.S
+ *
+ * System call common handling - if the return
+ * value from the system call is negative, then
+ * extract the magnitude and return it as errno and
+ * return -1, if the return value is 0 that is
+ * success case.
+ */
+
+	.type	__syscall_common,#function
+	.globl  __syscall_common
+	.balign 8
+
+__syscall_common:
+	cmp	x0, #0x0
+	b.ge	2f
+	neg	x0, x0
+	ldr	x8, 1f
+	str	x0, [x8]
+	mov	x0, #-1
+2:
+	ret
+1:
+	.dword	errno
diff --git a/usr/klibc/arch/arm64/sysstub.ph b/usr/klibc/arch/arm64/sysstub.ph
new file mode 100644
index 0000000..47cbfd9
--- /dev/null
+++ b/usr/klibc/arch/arm64/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/arm64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print  OUT "#include <asm/unistd.h>\n";
+    print  OUT "#include <klibc/asmmacros.h>\n";
+    print  OUT "	.text\n";
+    print  OUT "	.type	${fname}, #function\n";
+    print  OUT "	.globl	${fname}\n";
+    print  OUT "	.balign	8\n";
+    print  OUT "${fname}:\n";
+    print  OUT "	mov w8,__NR_${sname}\n";
+    print  OUT "	svc	0\n";
+    print  OUT "	b	__syscall_common\n";
+    print  OUT "	.size	${fname},.-${fname}\n";
+}
+
+1;
diff --git a/usr/klibc/arch/arm64/vfork.S b/usr/klibc/arch/arm64/vfork.S
new file mode 100644
index 0000000..494326c
--- /dev/null
+++ b/usr/klibc/arch/arm64/vfork.S
@@ -0,0 +1,34 @@
+/*
+ * arch/arm64/vfork.S
+ *
+ * vfork - a system call which must not use the stack.
+ */
+
+#include <klibc/asmmacros.h>
+#include <asm/unistd.h>
+
+	.type	vfork,#function
+	.globl	vfork
+	.balign	8
+
+vfork:
+	/* Prepare for the system call */
+        /* 1. Push the function pointer and argument location
+              on to the child process stack */
+        /* 2. Gather the Flags */
+        /* New sp is already in x1.  */
+        mov     x0, #0x4111     /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+        mov     x1, sp
+        mov     w8,__NR_clone
+        svc     0
+        cmp     x0, #0x0
+        b.ge    2f
+        neg     x0, x0
+        ldr     x8, 1f
+        str     x0, [x8]
+        mov     x0, #-1
+2:
+        ret
+1:
+        .dword   errno
+        .size   vfork,.-vfork
