diff options
Diffstat (limited to 'src/arch/arm32')
| -rw-r--r-- | src/arch/arm32/Makefile | 4 | ||||
| -rw-r--r-- | src/arch/arm32/Makefile.efi | 4 | ||||
| -rw-r--r-- | src/arch/arm32/Makefile.linux | 25 | ||||
| -rw-r--r-- | src/arch/arm32/core/arm32_bigint.c | 106 | ||||
| -rw-r--r-- | src/arch/arm32/core/pmccntr.S | 85 | ||||
| -rw-r--r-- | src/arch/arm32/include/bits/bigint.h | 107 | ||||
| -rw-r--r-- | src/arch/arm32/include/bits/profile.h | 19 | ||||
| -rw-r--r-- | src/arch/arm32/include/bits/setjmp.h (renamed from src/arch/arm32/include/setjmp.h) | 12 | ||||
| -rw-r--r-- | src/arch/arm32/include/bits/tcpip.h | 19 | ||||
| -rw-r--r-- | src/arch/arm32/include/gdbmach.h | 45 |
10 files changed, 195 insertions, 231 deletions
diff --git a/src/arch/arm32/Makefile b/src/arch/arm32/Makefile index 0c1cf99d1..070041734 100644 --- a/src/arch/arm32/Makefile +++ b/src/arch/arm32/Makefile @@ -1,3 +1,7 @@ +# Specify compressor +# +ZBIN = $(ZBIN32) + # ARM32-specific directories containing source files # SRCDIRS += arch/arm32/core diff --git a/src/arch/arm32/Makefile.efi b/src/arch/arm32/Makefile.efi index d720f34f0..9bd34383d 100644 --- a/src/arch/arm32/Makefile.efi +++ b/src/arch/arm32/Makefile.efi @@ -8,10 +8,6 @@ CFLAGS += -mfloat-abi=soft # ELF2EFI = $(ELF2EFI32) -# Specify EFI boot file -# -EFI_BOOT_FILE = bootarm.efi - # Include generic EFI Makefile # MAKEDEPS += arch/arm/Makefile.efi diff --git a/src/arch/arm32/Makefile.linux b/src/arch/arm32/Makefile.linux new file mode 100644 index 000000000..289118f29 --- /dev/null +++ b/src/arch/arm32/Makefile.linux @@ -0,0 +1,25 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The number of different ABIs for 32-bit ARM is insane. It is +# unclear whether or not unaligned accesses ought to work in a 32-bit +# Linux userspace binary. When running in QEMU, unaligned accesses +# result in a SIGBUS. Since this is likely to be the most common use +# case (for running self-tests on an x86 build machine), and since we +# don't particularly care about performance for Linux userspace +# binaries, force the compiler to never generate an unaligned access. +# +CFLAGS += -mno-unaligned-access + +# Inhibit the harmless warning about wchar_t size mismatch between the +# linux_api.o helper object and the rest of iPXE. +# +LINUX_CFLAGS += -Wl,--no-wchar-size-warning + +# Starting virtual address +# +LDFLAGS += -Ttext=0x10000 + +# Include generic Linux Makefile +# +MAKEDEPS += arch/arm/Makefile.linux +include arch/arm/Makefile.linux diff --git a/src/arch/arm32/core/arm32_bigint.c b/src/arch/arm32/core/arm32_bigint.c deleted file mode 100644 index 29fb40a7c..000000000 --- a/src/arch/arm32/core/arm32_bigint.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - uint32_t multiplicand_element; - uint32_t multiplier_element; - uint32_t *result_elements; - uint32_t discard_low; - uint32_t discard_high; - uint32_t discard_temp; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_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^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t" - "ldr %3, [%0]\n\t" - "adds %3, %1\n\t" - "stmia %0!, {%3}\n\t" - "ldr %3, [%0]\n\t" - "adcs %3, %2\n\t" - "stmia %0!, {%3}\n\t" - "bcc 2f\n\t" - "\n1:\n\t" - "ldr %3, [%0]\n\t" - "adcs %3, #0\n\t" - "stmia %0!, {%3}\n\t" - "bcs 1b\n\t" - "\n2:\n\t" - : "+l" ( result_elements ), - "=l" ( discard_low ), - "=l" ( discard_high ), - "=l" ( discard_temp ), - "+m" ( *result ) - : "l" ( multiplicand_element ), - "l" ( multiplier_element ) - : "cc" ); - } - } -} diff --git a/src/arch/arm32/core/pmccntr.S b/src/arch/arm32/core/pmccntr.S new file mode 100644 index 000000000..c2fbeff4f --- /dev/null +++ b/src/arch/arm32/core/pmccntr.S @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2024 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 ) + +/** @file + * + * Performance Monitor Cycle Counter (PMCCNTR) + * + */ + + .section ".note.GNU-stack", "", %progbits + .text + .arm + +/* + * PMCCNTR status + * + * bit 31 set if PMCCNTR availability is not yet determined + * bit 0 set if PMCCNTR is available + * + */ + .section ".data.pmccntr_status", "aw", %progbits + .globl pmccntr_status +pmccntr_status: + .word 0x80000000 + +/* + * Check PMCCNTR availability + * + * Must preserve all registers, and return with either PMCCNTR enabled + * or the Z flag set to indicate unavailability. + * + */ + .section ".text.pmccntr_check", "ax", %progbits + .globl pmccntr_check + .type pmccntr_check, %function +pmccntr_check: + /* Save registers */ + stmfd sp!, { r0, r1 } + /* Read CPSR.M (bits 3:0, always permitted in PL0) */ + mrs r0, cpsr + and r0, r0, #0x0000000f + /* Read PMUSERENR.EN (bit 0, always permitted in PL0) */ + mrc p15, 0, r1, c9, c14, 0 + and r1, r1, #0x00000001 + /* Check if we are in PL1+ or in PL0 with PMUSERENR.EN set */ + orrs r0, r0, r1 + /* If PMCCNTR is unavailable, exit with status=0 and ZF set */ + beq 1f + /* Set PMCR.E (bit 0), set exit status=1 and ZF clear */ + movs r0, #0x00000001 + mcr p15, 0, r0, c9, c12, 0 + /* Set PMCNTENSET.C (bit 31) */ + mov r1, #0x80000000 + mcr p15, 0, r1, c9, c12, 1 +1: /* Store PMCCNTR status */ + ldr r1, pmccntr_status_ptr + str r0, [r1] + /* Restore registers and return */ + ldmfd sp!, { r0, r1 } + bx lr +pmccntr_status_ptr: + .word pmccntr_status + .size pmccntr_check, . - pmccntr_check diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index e4b511da7..988bef5ff 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -43,8 +43,9 @@ bigint_init_raw ( uint32_t *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -54,8 +55,9 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, uint32_t *discard_end; uint32_t discard_addend_i; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %2, %0, %8, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %2, %0, %9, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldmia %0!, {%3}\n\t" "ldr %4, [%1]\n\t" @@ -68,9 +70,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, "=l" ( discard_end ), "=l" ( discard_addend_i ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( addend0 ), "1" ( value0 ), "l" ( size ) - : "cc" ); + : "0" ( addend0 ), "1" ( value0 ), + "l" ( size ) ); + return carry; } /** @@ -79,8 +83,9 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -90,8 +95,9 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, uint32_t *discard_end; uint32_t discard_subtrahend_i; uint32_t discard_value_i; + int borrow; - __asm__ __volatile__ ( "add %2, %0, %8, lsl #2\n\t" + __asm__ __volatile__ ( "add %2, %0, %9, lsl #2\n\t" "cmp %2, %0\n\t" /* set CF */ "\n1:\n\t" "ldmia %0!, {%3}\n\t" @@ -105,27 +111,30 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, "=l" ( discard_end ), "=l" ( discard_subtrahend_i ), "=l" ( discard_value_i ), + "=@cccc" ( borrow ), "+m" ( *value ) : "0" ( subtrahend0 ), "1" ( value0 ), - "l" ( size ) - : "cc" ); + "l" ( size ) ); + return borrow; } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( uint32_t *value0, unsigned int size ) { +static inline __attribute__ (( always_inline )) int +bigint_shl_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; uint32_t *discard_end; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %1, %0, %1, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldr %2, [%0]\n\t" "adcs %2, %2\n\t" @@ -135,26 +144,29 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) { : "=l" ( discard_value ), "=l" ( discard_end ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ) - : "cc" ); + : "0" ( value0 ), "1" ( size ) ); + return carry; } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( uint32_t *value0, unsigned int size ) { +static inline __attribute__ (( always_inline )) int +bigint_shr_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; uint32_t *discard_end; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %1, %0, %1, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldmdb %1!, {%2}\n\t" "rrxs %2, %2\n\t" @@ -164,9 +176,10 @@ bigint_ror_raw ( uint32_t *value0, unsigned int size ) { : "=l" ( discard_value ), "=l" ( discard_end ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ) - : "cc" ); + : "0" ( value0 ), "1" ( size ) ); + return carry; } /** @@ -217,25 +230,6 @@ bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0, } /** - * Test if bit is set in big integer - * - * @v value0 Element 0 of big integer - * @v size Number of elements - * @v bit Bit to test - * @ret is_set Bit is set - */ -static inline __attribute__ (( always_inline )) int -bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size, - unsigned int bit ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *value = - ( ( const void * ) value0 ); - unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) ); - unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) ); - - return ( value->element[index] & ( 1 << subindex ) ); -} - -/** * Find highest bit set in big integer * * @v value0 Element 0 of big integer @@ -309,10 +303,35 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, *(--out_byte) = *(value_byte++); } -extern void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier, + uint32_t *result, uint32_t *carry ) { + uint32_t discard_low; + uint32_t discard_high; + + __asm__ __volatile__ ( /* Perform multiplication */ + "umull %0, %1, %4, %5\n\t" + /* Accumulate result */ + "adds %2, %0\n\t" + "adc %1, #0\n\t" + /* Accumulate carry (cannot overflow) */ + "adds %2, %3\n\t" + "adc %3, %1, #0\n\t" + : "=r" ( discard_low ), + "=r" ( discard_high ), + "+r" ( *result ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) + : "cc" ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/arm32/include/bits/profile.h b/src/arch/arm32/include/bits/profile.h index 2b15d1604..31c321884 100644 --- a/src/arch/arm32/include/bits/profile.h +++ b/src/arch/arm32/include/bits/profile.h @@ -11,19 +11,30 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> +extern uint32_t pmccntr_status; + /** * Get profiling timestamp * * @ret timestamp Timestamp */ -static inline __attribute__ (( always_inline )) uint64_t +static inline __attribute__ (( always_inline )) unsigned long profile_timestamp ( void ) { uint32_t cycles; /* Read cycle counter */ - __asm__ __volatile__ ( "mcr p15, 0, %1, c9, c12, 0\n\t" - "mrc p15, 0, %0, c9, c13, 0\n\t" - : "=r" ( cycles ) : "r" ( 1 ) ); + __asm__ __volatile__ ( /* Check PMCCNTR status */ + "tst %0, %0\n\t" + /* Check availability if not yet known */ + "it mi\n\t" + "blxmi pmccntr_check\n\t" + /* Read PMCCNTR if available */ + "it ne\n\t" + "mrcne p15, 0, %0, c9, c13, 0\n\t" + "\n1:\n\t" + : "=r" ( cycles ) + : "0" ( pmccntr_status ) + : "cc", "lr" ); return cycles; } diff --git a/src/arch/arm32/include/setjmp.h b/src/arch/arm32/include/bits/setjmp.h index 4828b47a2..9ee264ecd 100644 --- a/src/arch/arm32/include/setjmp.h +++ b/src/arch/arm32/include/bits/setjmp.h @@ -1,5 +1,5 @@ -#ifndef _SETJMP_H -#define _SETJMP_H +#ifndef _BITS_SETJMP_H +#define _BITS_SETJMP_H FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); @@ -29,10 +29,4 @@ typedef struct { uint32_t lr; } jmp_buf[1]; -extern int __asmcall __attribute__ (( returns_twice )) -setjmp ( jmp_buf env ); - -extern void __asmcall __attribute__ (( noreturn )) -longjmp ( jmp_buf env, int val ); - -#endif /* _SETJMP_H */ +#endif /* _BITS_SETJMP_H */ diff --git a/src/arch/arm32/include/bits/tcpip.h b/src/arch/arm32/include/bits/tcpip.h deleted file mode 100644 index fc3c5b3ff..000000000 --- a/src/arch/arm32/include/bits/tcpip.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _BITS_TCPIP_H -#define _BITS_TCPIP_H - -/** @file - * - * Transport-network layer interface - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -static inline __attribute__ (( always_inline )) uint16_t -tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) { - - /* Not yet optimised */ - return generic_tcpip_continue_chksum ( partial, data, len ); -} - -#endif /* _BITS_TCPIP_H */ diff --git a/src/arch/arm32/include/gdbmach.h b/src/arch/arm32/include/gdbmach.h deleted file mode 100644 index cd152eedd..000000000 --- a/src/arch/arm32/include/gdbmach.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GDBMACH_H -#define GDBMACH_H - -/** @file - * - * GDB architecture specifics - * - * This file declares functions for manipulating the machine state and - * debugging context. - * - */ - -#include <stdint.h> - -typedef unsigned long gdbreg_t; - -/* Register snapshot */ -enum { - /* Not yet implemented */ - GDBMACH_NREGS, -}; - -#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) ) - -static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) pc; -} - -static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) { - /* Not yet implemented */ - ( void ) regs; - ( void ) step; -} - -static inline void gdbmach_breakpoint ( void ) { - /* Not yet implemented */ -} - -extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, - int enable ); -extern void gdbmach_init ( void ); - -#endif /* GDBMACH_H */ |
