From 9c83c3d3f443eb92f87dc87c7dcfe95577b95621 Mon Sep 17 00:00:00 2001 From: Simon South Date: Thu, 28 May 2020 14:29:55 -0400 Subject: [PATCH] Add support for aarch64 on GNU/Linux --- configure.ac | 10 +- src/arch/Makefile.am | 2 +- src/arch/aarch64.h | 110 ++++++++++++++++ src/os/linux/Makefile.am | 2 +- src/os/linux/aarch64/Makefile.am | 28 ++++ src/os/linux/aarch64/callNative.S | 212 ++++++++++++++++++++++++++++++ src/os/linux/aarch64/dll_md.c | 59 +++++++++ src/os/linux/aarch64/init.c | 51 +++++++ 8 files changed, 469 insertions(+), 5 deletions(-) create mode 100644 src/arch/aarch64.h create mode 100644 src/os/linux/aarch64/Makefile.am create mode 100644 src/os/linux/aarch64/callNative.S create mode 100644 src/os/linux/aarch64/dll_md.c create mode 100644 src/os/linux/aarch64/init.c diff --git a/configure.ac b/configure.ac index ccd530f..707f281 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,7 @@ amd64-*-freebsd*) host_os=bsd libdl_needed=no ;; arm*-*-linux*) host_cpu=arm host_os=linux ;; arm*-*-openbsd*) host_cpu=arm host_os=bsd libdl_needed=no ;; arm*-*-freebsd*) host_cpu=arm host_os=bsd libdl_needed=no ;; +aarch64*-*-linux*) host_cpu=aarch64 host_os=linux ;; powerpc*-*-linux*) host_cpu=powerpc host_os=linux ;; powerpc*-*-openbsd*) host_cpu=powerpc host_os=bsd libdl_needed=no ;; powerpc*-*-freebsd*) host_cpu=powerpc host_os=bsd libdl_needed=no ;; @@ -149,9 +150,11 @@ AC_ARG_ENABLE(runtime-reloc-checks, AC_ARG_ENABLE(int-inlining, [AS_HELP_STRING(--enable-int-inlining,enable inline threaded version of the interpreter - (by default enabled on x86_64, i386 and powerpc, disabled otherwise))],, - [if test "$host_cpu" = x86_64 -o "$host_cpu" = i386 -o "$host_cpu" = powerpc && \ - test "$cross_compiling" = no -o "$enable_runtime_reloc_checks" != no; then + (by default enabled on x86_64, i386, powerpc and aarch64, + disabled otherwise))],, + [if test "$host_cpu" = x86_64 -o "$host_cpu" = i386 -o "$host_cpu" = powerpc -o \ + "$host_cpu" = aarch64 && test "$cross_compiling" = no -o \ + "$enable_runtime_reloc_checks" != no; then enable_int_inlining=yes else enable_int_inlining=no @@ -298,6 +301,7 @@ AC_CONFIG_FILES( src/os/linux/x86_64/Makefile \ src/os/linux/parisc/Makefile \ src/os/linux/mips/Makefile \ + src/os/linux/aarch64/Makefile \ src/os/darwin/i386/Makefile \ src/os/darwin/arm/Makefile \ src/os/darwin/powerpc/Makefile \ diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am index 078c1de..afb26d1 100644 --- a/src/arch/Makefile.am +++ b/src/arch/Makefile.am @@ -19,4 +19,4 @@ ## Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ## -EXTRA_DIST = powerpc.h arm.h i386.h x86_64.h parisc.h mips.h +EXTRA_DIST = powerpc.h arm.h i386.h x86_64.h parisc.h mips.h aarch64.h diff --git a/src/arch/aarch64.h b/src/arch/aarch64.h new file mode 100644 index 0000000..c96aa9f --- /dev/null +++ b/src/arch/aarch64.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 + * Robert Lougher . + * Copyright (C) 2020 Simon South . + * + * This file is part of JamVM. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#define OS_ARCH "aarch64" + +#define HANDLER_TABLE_T static const void +#define DOUBLE_1_BITS 0x3ff0000000000000LL + +#define READ_DBL(v,p,l) v = ((u8)p[0]<<56)|((u8)p[1]<<48)|((u8)p[2]<<40) \ + |((u8)p[3]<<32)|((u8)p[4]<<24)|((u8)p[5]<<16) \ + |((u8)p[6]<<8)|(u8)p[7]; p+=8 + +/* Needed for i386 -- empty here */ +#define FPU_HACK + +#define COMPARE_AND_SWAP_64(addr, old_val, new_val) \ +({ \ + int result, read_val; \ + __asm__ __volatile__ (" \ + 1: ldaxr %2, %1; \ + cmp %2, %3; \ + b.ne 2f; \ + stlxr %w0, %4, %1; \ + cmp %w0, wzr; \ + b.ne 1b; \ + 2: cset %w0, eq;" \ + : "=&r" (result), "+Q" (*addr), "=&r" (read_val) \ + : "r" (old_val), "r" (new_val) \ + : "cc"); \ + result; \ +}) + +#define COMPARE_AND_SWAP(addr, old_val, new_val) \ + COMPARE_AND_SWAP_64(addr, old_val, new_val) + +#define LOCKWORD_READ(addr) \ +({ \ + uintptr_t result; \ + __asm__ __volatile__ (" \ + ldar %0, %1;" \ + : "=r" (result) \ + : "Q" (*addr) \ + : "cc"); \ + result; \ +}) + +#define LOCKWORD_WRITE(addr, value) \ +({ \ + __asm__ __volatile__ (" \ + stlr %1, %0;" \ + : "=Q" (*addr) \ + : "r" (value) \ + : "cc"); \ +}) + +#define LOCKWORD_COMPARE_AND_SWAP(addr, old_val, new_val) \ + COMPARE_AND_SWAP_64(addr, old_val, new_val) + +#define FLUSH_CACHE(addr, length) \ +{ \ + uintptr_t start = (uintptr_t) (addr); \ + uintptr_t end = start + length; \ + uintptr_t i; \ + \ + for(i = start & aarch64_data_cache_line_mask; \ + i < end; \ + i += aarch64_data_cache_line_len) \ + __asm__ ("dc cvau, %0" :: "r" (i)); \ + \ + __asm__ ("dsb ish"); \ + \ + for(i = start & aarch64_instruction_cache_line_mask; \ + i < end; \ + i += aarch64_instruction_cache_line_len) \ + __asm__ ("ic ivau, %0" :: "r" (i)); \ + \ + __asm__ ("dsb ish; isb"); \ +} + +#define MBARRIER() __asm__ ("dmb ish" ::: "memory") +#define UNLOCK_MBARRIER() __asm__ ("dmb ish" ::: "memory") +#define JMM_LOCK_MBARRIER() __asm__ ("dmb ish" ::: "memory") +#define JMM_UNLOCK_MBARRIER() JMM_LOCK_MBARRIER() + +/* Defined in src/os/linux/aarch64/init.c */ +extern unsigned char aarch64_data_cache_line_len; +extern uintptr_t aarch64_data_cache_line_mask; +extern unsigned char aarch64_instruction_cache_line_len; +extern uintptr_t aarch64_instruction_cache_line_mask; diff --git a/src/os/linux/Makefile.am b/src/os/linux/Makefile.am index aa29be1..d582b97 100644 --- a/src/os/linux/Makefile.am +++ b/src/os/linux/Makefile.am @@ -20,7 +20,7 @@ ## SUBDIRS = @arch@ -DIST_SUBDIRS = powerpc arm i386 x86_64 parisc mips +DIST_SUBDIRS = powerpc arm i386 x86_64 parisc mips aarch64 noinst_LTLIBRARIES = libos.la libos_la_SOURCES = os.c diff --git a/src/os/linux/aarch64/Makefile.am b/src/os/linux/aarch64/Makefile.am new file mode 100644 index 0000000..1024c3a --- /dev/null +++ b/src/os/linux/aarch64/Makefile.am @@ -0,0 +1,28 @@ +## +## Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2012 +## Robert Lougher . +## +## File added by Simon South . +## +## This file is part of JamVM. +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2, +## or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## + +noinst_LTLIBRARIES = libnative.la +libnative_la_SOURCES = init.c dll_md.c callNative.S + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +AM_CCASFLAGS = -I$(top_builddir)/src diff --git a/src/os/linux/aarch64/callNative.S b/src/os/linux/aarch64/callNative.S new file mode 100644 index 0000000..e067c4f --- /dev/null +++ b/src/os/linux/aarch64/callNative.S @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2008, 2009, 2011, 2012 Robert Lougher . + * Copyright (C) 2020 Simon South . + * + * This file is part of JamVM. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#ifndef USE_FFI + .text + .arch armv8-a + .align 2 + .global callJNIMethod + .type callJNIMethod,function + +/* + * Arguments passed in: + * + * x0 JNIEnv + * x1 class or NULL + * x2 sig + * w3 extra arg + * x4 ostack + * x5 function pntr + * w6 args count + */ + +/* Register usage: + * + * x20 ostack + * x19 sig pntr + * x16 function pntr + * x15 ostack pntr + * x14 args pntr + * x13 float/double handler + * x12 int/long handler + * w11 fp regs remaining + * w10 int regs remaining + * x9 scratch + * x2-x7 outgoing int args + * x1 outgoing class or this pntr + * x0 outgoing JNIEnv (as passed in) + * + * d0 - d7 outgoing float args + */ + +callJNIMethod: + stp x29, x30, [sp, #-32]! + mov x29, sp + stp x19, x20, [x29, #16] + + sub sp, sp, w3 /* allocate room for stacked args */ + mov x14, sp + + mov x20, x4 /* preserve ostack */ + add x19, x2, #1 /* init sig pntr -- skipping '(' */ + + mov x16, x5 /* save function pntr */ + mov x15, x20 /* init ostack pntr */ + + adr x13, fp_reg_handlers-8 + adr x12, int_reg_handlers-8 + + mov w11, #8 /* fp regs remaining */ + mov w10, #6 /* int regs remaining */ + + cbnz x1, scan_sig /* is method non-static? */ + ldr x1, [x15], #8 /* yes, load x1 with "this" */ + +scan_sig: + ldrb w9, [x19], #1 /* get next sig char */ + + cmp w9, #41 /* ')' */ + b.eq done + + cmp w9, #74 /* 'J' */ + b.eq long + + cmp w9, #70 /* 'F' */ + b.eq float + + cmp w9, #68 /* 'D' */ + b.eq double + +skip_brackets: + cmp w9, #91 /* '[' */ + b.ne 1f + ldrb w9, [x19], #1 + b skip_brackets +1: + cmp w9, #76 /* 'L' */ + b.ne int + +skip_ref: + ldrb w9, [x19], #1 + cmp w9, #59 /* ';' */ + b.ne skip_ref + +int: + ldr x9, [x15], #8 + cbz w10, stack_push + +load_int_reg: + sub w10, w10, #1 + add x12, x12, #8 + br x12 + +int_reg_handlers: + mov x2, x9 + b scan_sig + mov x3, x9 + b scan_sig + mov x4, x9 + b scan_sig + mov x5, x9 + b scan_sig + mov x6, x9 + b scan_sig + mov x7, x9 + b scan_sig + +long: + ldr x9, [x15], #16 + cbz w10, stack_push + b load_int_reg + +float: + ldr w9, [x15], #8 + cbz w11, stack_push + b load_fp_reg + +double: + ldr x9, [x15], #16 + cbz w11, stack_push + +load_fp_reg: + sub w11, w11, #1 + add x13, x13, #8 + br x13 + +fp_reg_handlers: + fmov d0, x9 + b scan_sig + fmov d1, x9 + b scan_sig + fmov d2, x9 + b scan_sig + fmov d3, x9 + b scan_sig + fmov d4, x9 + b scan_sig + fmov d5, x9 + b scan_sig + fmov d6, x9 + b scan_sig + fmov d7, x9 + b scan_sig + +stack_push: + str x9, [x14], #8 + b scan_sig + +done: + /* Call the function */ + blr x16 + + mov sp, x29 /* Pop argument area */ + + ldrb w9, [x19] /* Return type */ + + cmp w9, #86 /* 'V' */ + b.eq return + + cmp w9, #68 /* 'D' */ + b.ne 2f + str d0, [x20], #16 + b return +2: + cmp w9, #70 /* 'F' */ + b.ne 3f + str s0, [x20], #8 + b return +3: + cmp w9, #74 /* 'J' */ + b.ne 4f + str x0, [x20], #16 + b return +4: + str x0, [x20], #8 + +return: + mov x0, x20 /* return ostack */ + + ldp x19, x20, [x29, #16] + ldp x29, x30, [sp], #32 + ret +#endif diff --git a/src/os/linux/aarch64/dll_md.c b/src/os/linux/aarch64/dll_md.c new file mode 100644 index 0000000..189f8a8 --- /dev/null +++ b/src/os/linux/aarch64/dll_md.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011 + * Robert Lougher . + * Copyright (C) 2020 Simon South . + * + * This file is part of JamVM. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "jam.h" + +#ifndef USE_FFI + +int nativeExtraArg(MethodBlock *mb) { + char *sig = mb->type; + int stack_args = 0; + int int_args = 6; + int fp_args = 8; + + while(*++sig != ')') + switch(*sig) { + case 'F': + case 'D': + if(fp_args == 0) + stack_args += 8; + else + fp_args--; + + default: + if(int_args == 0) + stack_args += 8; + else + int_args--; + + if(*sig == '[') + while(*++sig == '['); + if(*sig == 'L') + while(*++sig != ';'); + break; + } + + /* Ensure the stack remains 16 byte aligned. */ + return (stack_args + 15) & ~15; +} + +#endif diff --git a/src/os/linux/aarch64/init.c b/src/os/linux/aarch64/init.c new file mode 100644 index 0000000..e03b446 --- /dev/null +++ b/src/os/linux/aarch64/init.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 + * Robert Lougher . + * Copyright (C) 2020 Simon South . + * + * This file is part of JamVM. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "arch/aarch64.h" + +/* Length in bytes of the smallest line in the host system's data cache */ +unsigned char aarch64_data_cache_line_len; + +/* Mask used to align a virtual address to a line in the data cache */ +uintptr_t aarch64_data_cache_line_mask; + +/* Length in bytes of the smallest line in the host system's instruction + cache */ +unsigned char aarch64_instruction_cache_line_len; + +/* Mask used to align a virtual address to a line in the instruction cache */ +uintptr_t aarch64_instruction_cache_line_mask; + +void initialisePlatform() { + unsigned int cache_type; + + /* Extract information from the cache-type register, which describes aspects + of the host's cache configuration */ + __asm__ ("mrs %0, ctr_el0" : "=r" (cache_type)); + + aarch64_data_cache_line_len = 4 << ((cache_type >> 16) & 0x0f); + aarch64_data_cache_line_mask = ~(aarch64_data_cache_line_len - 1); + + aarch64_instruction_cache_line_len = 4 << (cache_type & 0x0f); + aarch64_instruction_cache_line_mask = + ~(aarch64_instruction_cache_line_len - 1); +} -- 2.26.2