diff options
| author | Michael Brown | 2016-05-08 01:20:20 +0200 |
|---|---|---|
| committer | Michael Brown | 2016-05-08 01:20:20 +0200 |
| commit | 17c6f322eef5e0a2250a89b140486cf07598d2fa (patch) | |
| tree | c67442d1e56245b42f9e7b98f9fa0e7b9cc24b1d /src/arch/arm64/core | |
| parent | [arm] Split out 32-bit-specific code to arch/arm32 (diff) | |
| download | ipxe-17c6f322eef5e0a2250a89b140486cf07598d2fa.tar.gz ipxe-17c6f322eef5e0a2250a89b140486cf07598d2fa.tar.xz ipxe-17c6f322eef5e0a2250a89b140486cf07598d2fa.zip | |
[arm] Add support for 64-bit ARM (Aarch64)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/arm64/core')
| -rw-r--r-- | src/arch/arm64/core/arm64_bigint.c | 103 | ||||
| -rw-r--r-- | src/arch/arm64/core/setjmp.S | 56 |
2 files changed, 159 insertions, 0 deletions
diff --git a/src/arch/arm64/core/arm64_bigint.c b/src/arch/arm64/core/arm64_bigint.c new file mode 100644 index 000000000..bc4ee9a00 --- /dev/null +++ b/src/arch/arm64/core/arm64_bigint.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>. + * + * 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 of the + * License, or 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <string.h> +#include <ipxe/bigint.h> + +/** @file + * + * Big integer support + */ + +/** + * Multiply big integers + * + * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplier0 Element 0 of big integer to be multiplied + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements + */ +void bigint_multiply_raw ( const uint64_t *multiplicand0, + const uint64_t *multiplier0, + uint64_t *result0, unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = + ( ( const void * ) multiplicand0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = + ( ( const void * ) multiplier0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = + ( ( void * ) result0 ); + unsigned int i; + unsigned int j; + uint64_t multiplicand_element; + uint64_t multiplier_element; + uint64_t *result_elements; + uint64_t discard_low; + uint64_t discard_high; + uint64_t discard_temp_low; + uint64_t discard_temp_high; + + /* Zero result */ + memset ( result, 0, sizeof ( *result ) ); + + /* Multiply integers one element at a time */ + for ( i = 0 ; i < size ; i++ ) { + multiplicand_element = multiplicand->element[i]; + for ( j = 0 ; j < size ; j++ ) { + multiplier_element = multiplier->element[j]; + result_elements = &result->element[ i + j ]; + /* Perform a single multiply, and add the + * resulting double-element into the result, + * carrying as necessary. The carry can + * never overflow beyond the end of the + * result, since: + * + * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + */ + __asm__ __volatile__ ( "mul %1, %6, %7\n\t" + "umulh %2, %6, %7\n\t" + "ldp %3, %4, [%0]\n\t" + "adds %3, %3, %1\n\t" + "adcs %4, %4, %2\n\t" + "stp %3, %4, [%0], #16\n\t" + "bcc 2f\n\t" + "\n1:\n\t" + "ldr %3, [%0]\n\t" + "adcs %3, %3, xzr\n\t" + "str %3, [%0], #8\n\t" + "bcs 1b\n\t" + "\n2:\n\t" + : "+r" ( result_elements ), + "=&r" ( discard_low ), + "=&r" ( discard_high ), + "=r" ( discard_temp_low ), + "=r" ( discard_temp_high ), + "+m" ( *result ) + : "r" ( multiplicand_element ), + "r" ( multiplier_element ) + : "cc" ); + } + } +} diff --git a/src/arch/arm64/core/setjmp.S b/src/arch/arm64/core/setjmp.S new file mode 100644 index 000000000..fa47aa0af --- /dev/null +++ b/src/arch/arm64/core/setjmp.S @@ -0,0 +1,56 @@ +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + + .text + + /* Must match jmp_buf structure layout */ + .struct 0 +env_x19_x20: .quad 0, 0 +env_x21_x22: .quad 0, 0 +env_x23_x24: .quad 0, 0 +env_x25_x26: .quad 0, 0 +env_x27_x28: .quad 0, 0 +env_x29_x30: .quad 0, 0 +env_sp: .quad 0 + .previous + +/* + * Save stack context for non-local goto + */ + .globl setjmp + .type setjmp, %function +setjmp: + /* Store registers */ + stp x19, x20, [x0, #env_x19_x20] + stp x21, x22, [x0, #env_x21_x22] + stp x23, x24, [x0, #env_x23_x24] + stp x25, x26, [x0, #env_x25_x26] + stp x27, x28, [x0, #env_x27_x28] + stp x29, x30, [x0, #env_x29_x30] + mov x16, sp + str x16, [x0, #env_sp] + /* Return 0 when returning as setjmp() */ + mov x0, #0 + ret + .size setjmp, . - setjmp + +/* + * Non-local jump to a saved stack context + */ + .globl longjmp + .type longjmp, %function +longjmp: + /* Restore registers */ + ldp x19, x20, [x0, #env_x19_x20] + ldp x21, x22, [x0, #env_x21_x22] + ldp x23, x24, [x0, #env_x23_x24] + ldp x25, x26, [x0, #env_x25_x26] + ldp x27, x28, [x0, #env_x27_x28] + ldp x29, x30, [x0, #env_x29_x30] + ldr x16, [x0, #env_sp] + mov sp, x16 + /* Force result to non-zero */ + cmp w1, #0 + csinc w0, w1, w1, ne + /* Return to setjmp() caller */ + br x30 + .size longjmp, . - longjmp |
