From 975f053ddf7d8fc1248610dc08dc9db5c667a2a9 Mon Sep 17 00:00:00 2001 From: James Bornholt Date: Sat, 5 Dec 2020 17:12:37 -0600 Subject: [PATCH] Add aarch64 support on Linux and macOS --- .travis.yml | 4 ++ build.rs | 4 +- src/detail/aarch64_unix.rs | 65 ++++++++++++++++++++ src/detail/asm/asm_aarch64_aapcs_elf_gas.S | 50 +++++++++++++++ src/detail/asm/asm_aarch64_aapcs_macho_gas.S | 41 ++++++++++++ src/detail/mod.rs | 5 ++ src/stack/mod.rs | 4 ++ 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 src/detail/aarch64_unix.rs create mode 100644 src/detail/asm/asm_aarch64_aapcs_elf_gas.S create mode 100644 src/detail/asm/asm_aarch64_aapcs_macho_gas.S diff --git a/.travis.yml b/.travis.yml index e761891..4a0c3d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,10 @@ os: - linux - osx +arch: +- amd64 +- arm64 + rust: - stable - nightly diff --git a/build.rs b/build.rs index 02c39f8..bcd189a 100644 --- a/build.rs +++ b/build.rs @@ -21,7 +21,7 @@ fn main() { let arch = match target.split('-').next().unwrap() { // "arm" | "armv7" | "armv7s" => "arm", - // "arm64" | "aarch64" => "arm64", + "arm64" | "aarch64" => "aarch64", // "x86" | "i386" | "i486" | "i586" | "i686" => "i386", // "mips" | "mipsel" => "mips32", // "powerpc" => "ppc32", @@ -33,7 +33,7 @@ fn main() { }; let abi = match arch { - "arm" | "arm64" => "aapcs", + "arm" | "aarch64" => "aapcs", "mips32" => "o32", _ => { if is_win { diff --git a/src/detail/aarch64_unix.rs b/src/detail/aarch64_unix.rs new file mode 100644 index 0000000..74535e8 --- /dev/null +++ b/src/detail/aarch64_unix.rs @@ -0,0 +1,65 @@ +use crate::detail::align_down; +use crate::reg_context::InitFn; +use crate::stack::Stack; + +#[link(name = "asm", kind = "static")] +extern "C" { + pub fn bootstrap_green_task(); + pub fn prefetch(data: *const usize); + pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers); +} + +#[repr(C)] +#[derive(Debug)] +pub struct Registers { + // We only save the 13 callee-saved registers: + // x19--x28, fp (x29), lr (x30), sp + gpr: [usize; 13], +} + +impl Registers { + pub fn new() -> Registers { + Registers { gpr: [0; 13] } + } + + #[inline] + pub fn prefetch(&self) { + unsafe { + prefetch(self as *const _ as *const usize); + prefetch(self.gpr[1] as *const usize); + } + } +} + +pub fn initialize_call_frame( + regs: &mut Registers, + fptr: InitFn, + arg: usize, + arg2: *mut usize, + stack: &Stack, +) { + // Callee-saved registers start at x19 + const X19: usize = 19 - 19; + const X20: usize = 20 - 19; + const X21: usize = 21 - 19; + const FP: usize = 29 - 19; + const LR: usize = 30 - 19; + const SP: usize = 31 - 19; + + let sp = align_down(stack.end()); + + // These registers are frobbed by bootstrap_green_task into the right + // location so we can invoke the "real init function", `fptr`. + regs.gpr[X19] = arg; + regs.gpr[X20] = arg2 as usize; + regs.gpr[X21] = fptr as usize; + + // Last frame pointer should be 0 + regs.gpr[FP] = 0; + + regs.gpr[LR] = bootstrap_green_task as usize; + + // setup the init stack + // this is prepared for the swap context + regs.gpr[SP] = sp as usize; +} diff --git a/src/detail/asm/asm_aarch64_aapcs_elf_gas.S b/src/detail/asm/asm_aarch64_aapcs_elf_gas.S new file mode 100644 index 0000000..9b020d5 --- /dev/null +++ b/src/detail/asm/asm_aarch64_aapcs_elf_gas.S @@ -0,0 +1,50 @@ +.text +.globl prefetch +.type prefetch,@function +.align 16 +prefetch: + prfm pldl1keep, [x0] + ret +.size prefetch,.-prefetch + +.text +.globl bootstrap_green_task +.type bootstrap_green_task,@function +.align 16 +bootstrap_green_task: + mov x0, x19 // arg0 + mov x1, x20 // arg1 + mov x30, x21 // return address (lr == x30 but GCC rejects `lr`) + ret +.size bootstrap_green_task,.-bootstrap_green_task + +.text +.globl swap_registers +.type swap_registers,@function +.align 16 +swap_registers: + 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] + + mov x2, sp + str x2, [x0, #96] + + ldp x19, x20, [x1, #0] + ldp x21, x22, [x1, #16] + ldp x23, x24, [x1, #32] + ldp x25, x26, [x1, #48] + ldp x27, x28, [x1, #64] + ldp x29, x30, [x1, #80] + + ldr x2, [x1, #96] + mov sp, x2 + + ret +.size swap_registers,.-swap_registers + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/src/detail/asm/asm_aarch64_aapcs_macho_gas.S b/src/detail/asm/asm_aarch64_aapcs_macho_gas.S new file mode 100644 index 0000000..3f47052 --- /dev/null +++ b/src/detail/asm/asm_aarch64_aapcs_macho_gas.S @@ -0,0 +1,41 @@ +.text +.globl _prefetch +.align 8 +_prefetch: + prfm pldl1keep, [x0] + ret + +.text +.globl _bootstrap_green_task +.align 8 +_bootstrap_green_task: + mov x0, x19 // arg0 + mov x1, x20 // arg1 + mov lr, x21 // return address + ret + +.text +.globl _swap_registers +.align 8 +_swap_registers: + 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] + + mov x2, sp + str x2, [x0, #96] + + ldp x19, x20, [x1, #0] + ldp x21, x22, [x1, #16] + ldp x23, x24, [x1, #32] + ldp x25, x26, [x1, #48] + ldp x27, x28, [x1, #64] + ldp x29, x30, [x1, #80] + + ldr x2, [x1, #96] + mov sp, x2 + + ret diff --git a/src/detail/mod.rs b/src/detail/mod.rs index 406b058..3579b1e 100644 --- a/src/detail/mod.rs +++ b/src/detail/mod.rs @@ -29,6 +29,10 @@ pub mod asm; #[path = "x86_64_windows.rs"] pub mod asm; +#[cfg(all(unix, target_arch = "aarch64"))] +#[path = "aarch64_unix.rs"] +pub mod asm; + pub use self::asm::{initialize_call_frame, prefetch, swap_registers, Registers}; #[inline] @@ -39,6 +43,7 @@ fn align_down(sp: *mut usize) -> *mut usize { // ptr::mut_offset is positive isizes only #[inline] +#[allow(unused)] fn mut_offset(ptr: *mut T, count: isize) -> *mut T { // use std::mem::size_of; // (ptr as isize + count * (size_of::() as isize)) as *mut T diff --git a/src/stack/mod.rs b/src/stack/mod.rs index 5527ec9..30ab28f 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -13,6 +13,10 @@ use std::ptr; #[path = "unix.rs"] pub mod sys; +#[cfg(all(unix, target_arch = "aarch64"))] +#[path = "unix.rs"] +pub mod sys; + #[cfg(all(windows, target_arch = "x86_64"))] #[path = "windows.rs"] pub mod sys;