From a44154f7a18496cc3e5fc0b1b2ea69523ebc623a Mon Sep 17 00:00:00 2001 From: Simon South <simon@simonsouth.net> Date: Mon, 1 Jun 2020 07:09:34 -0400 Subject: [PATCH] Add support for aarch64 on GNU/Linux --- AUTHORS | 1 + README | 2 +- configure.ac | 7 +- src/arch/Makefile.am | 2 +- src/arch/aarch64.h | 147 +++++++++++++++++++++ src/jam.c | 3 +- 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 +++++++ 11 files changed, 508 insertions(+), 6 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/AUTHORS b/AUTHORS index e1334fe..6fd0eeb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Robert Lougher <rob@jamvm.org.uk> +Simon South <simon@simonsouth.net> diff --git a/README b/README index c9d80bb..0e93d00 100644 --- a/README +++ b/README @@ -77,7 +77,7 @@ versions of JamVM also includes stubs for common method signatures. The following platforms/architectures are recognised by configure. Those marked with * must be configured to use libffi. -- Linux: x86, x86_64, ARM, PowerPC, PowerPC64(*), MIPS, HPPA +- Linux: x86, x86_64, ARM, ARM64, PowerPC, PowerPC64(*), MIPS, HPPA - FreeBSD: x86, x86_64, ARM, PowerPC, PowerPC64(*), SPARC(*) - OpenBSD: x86, x86_64, ARM, PowerPC, PowerPC64(*), SPARC(*) - Mac OS X/Darwin: x86, x86_64, ARM, PowerPC, PowerPC64 diff --git a/configure.ac b/configure.ac index 138b7e6..e7051d7 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,7 @@ x86_64-*-freebsd*) host_os=bsd libdl_needed=no ;; arm*-*-linux*) host_cpu=arm host_os=linux interp_cflags=-marm ;; 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 ;; @@ -155,10 +156,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, powerpc, mips and arm, + (by default enabled on x86_64, i386, powerpc, mips, arm and aarch64, disabled otherwise))],, [if test "$host_cpu" = x86_64 -o "$host_cpu" = i386 -o "$host_cpu" = x86 -o \ - "$host_cpu" = powerpc -o "$host_cpu" = arm -o "$host_cpu" = mips; then + "$host_cpu" = powerpc -o "$host_cpu" = arm -o "$host_cpu" = mips -o \ + "$host_cpu" = aarch64; then enable_int_inlining=yes else enable_int_inlining=no @@ -407,6 +409,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 7580a1b..4e2a4f9 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 sparc.h +EXTRA_DIST = powerpc.h arm.h i386.h x86_64.h parisc.h mips.h sparc.h aarch64.h diff --git a/src/arch/aarch64.h b/src/arch/aarch64.h new file mode 100644 index 0000000..1912e79 --- /dev/null +++ b/src/arch/aarch64.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 + * Robert Lougher <rob@jamvm.org.uk>. + * Copyright (C) 2020 Simon South <simon@simonsouth.net>. + * + * 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 <stdint.h> + +#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_32(addr, old_val, new_val) \ +({ \ + int result, read_val; \ + __asm__ __volatile__ (" \ + 1: ldaxr %w2, %1; \ + cmp %w2, %w3; \ + b.ne 2f; \ + stlxr %w0, %w4, %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 GEN_REL_JMP(target_addr, patch_addr, patch_size) \ +({ \ + int patched = FALSE; \ + \ + if(patch_size >= 4) { \ + /* Guard against the pointer difference being \ + larger than the signed range */ \ + long long offset = (uintptr_t)(target_addr) - \ + (uintptr_t)(patch_addr); \ + \ + if(offset >= -1<<28 && offset < 1<<28) { \ + *(uint32_t*)(patch_addr) = offset>>2 & 0x03ffffff \ + | 0x14000000; \ + patched = TRUE; \ + } \ + } \ + patched; \ +}) + +#define MBARRIER() __asm__ ("dmb ish" ::: "memory") +#define RMBARRIER() __asm__ ("dmb ishld" ::: "memory") +#define WMBARRIER() __asm__ ("dmb ishst" ::: "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/jam.c b/src/jam.c index 052f84a..c97524a 100644 --- a/src/jam.c +++ b/src/jam.c @@ -98,7 +98,8 @@ void showUsage(char *name) { void showVersionAndCopyright() { printf("java version \"%s\"\n", JAVA_COMPAT_VERSION); printf("JamVM version %s\n", VERSION); - printf("Copyright (C) 2003-2014 Robert Lougher <rob@jamvm.org.uk>\n\n"); + printf("Copyright (C) 2003-2014 Robert Lougher <rob@jamvm.org.uk>\n"); + printf("Portions Copyright (C) 2020 Simon South <simon@simonsouth.net>\n\n"); printf("This program is free software; you can redistribute it and/or\n"); printf("modify it under the terms of the GNU General Public License\n"); printf("as published by the Free Software Foundation; either version 2,\n"); diff --git a/src/os/linux/Makefile.am b/src/os/linux/Makefile.am index 542094e..83e7dfe 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..0e5134f --- /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 <rob@jamvm.org.uk>. +## +## File added by Simon South <simon@simonsouth.net>. +## +## 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 <rob@jamvm.org.uk>. + * Copyright (C) 2020 Simon South <simon@simonsouth.net>. + * + * 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 <rob@jamvm.org.uk>. + * Copyright (C) 2020 Simon South <simon@simonsouth.net>. + * + * 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..b21dc55 --- /dev/null +++ b/src/os/linux/aarch64/init.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 + * Robert Lougher <rob@jamvm.org.uk>. + * Copyright (C) 2020 Simon South <simon@simonsouth.net>. + * + * 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