| #ifndef _BITS_BIGINT_H | |
| #define _BITS_BIGINT_H | |
| /** @file | |
| * | |
| * Big integer support | |
| */ | |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | |
| /** Element of a big integer */ | |
| typedef unsigned long bigint_element_t; | |
| /** | |
| * Add big integers | |
| * | |
| * @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 )) int | |
| bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, | |
| unsigned int size ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) *addend = | |
| ( ( void * ) addend0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( void * ) value0 ); | |
| unsigned long discard_offset; | |
| unsigned long discard_temp; | |
| unsigned int index_carry; | |
| __asm__ ( /* Zero offset and clear carry-in */ | |
| "xgr %0, %0\n\t" | |
| /* Add element by element */ | |
| "\n1:\n\t" | |
| "lg %1, %O3(%0, %R3)\n\t" | |
| "alcg %1, %O4(%0, %R4)\n\t" | |
| "stg %1, %O3(%0, %R3)\n\t" | |
| "la %0, 8(%0)\n\t" | |
| "brct %2, 1b\n\t" | |
| /* Obtain carry-out */ | |
| "alcr %2, %2\n\t" | |
| : "=&a" ( discard_offset ), | |
| "=&r" ( discard_temp ), | |
| "=&r" ( index_carry ), | |
| "+S" ( *value ) | |
| : "S" ( *addend ), | |
| "2" ( size ) | |
| : "cc" ); | |
| return index_carry; | |
| } | |
| /** | |
| * Subtract big integers | |
| * | |
| * @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 )) int | |
| bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, | |
| unsigned int size ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) *subtrahend = | |
| ( ( void * ) subtrahend0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( void * ) value0 ); | |
| unsigned long discard_offset; | |
| unsigned long discard_temp; | |
| unsigned int index_borrow; | |
| __asm__ ( /* Zero offset and clear (inverted) borrow-in */ | |
| "slgr %0, %0\n\t" | |
| /* Subtract element by element */ | |
| "\n1:\n\t" | |
| "lg %1, %O3(%0, %R3)\n\t" | |
| "slbg %1, %O4(%0, %R4)\n\t" | |
| "stg %1, %O3(%0, %R3)\n\t" | |
| "la %0, 8(%0)\n\t" | |
| "brct %2, 1b\n\t" | |
| /* Obtain (negative) borrow-out */ | |
| "slbr %2, %2\n\t" | |
| : "=&a" ( discard_offset ), | |
| "=&r" ( discard_temp ), | |
| "=&r" ( index_borrow ), | |
| "+S" ( *value ) | |
| : "S" ( *subtrahend ), | |
| "2" ( size ) | |
| : "cc" ); | |
| return ( -index_borrow ); | |
| } | |
| /** | |
| * 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 )) int | |
| bigint_shl_raw ( unsigned long *value0, unsigned int size ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( void * ) value0 ); | |
| unsigned long discard_offset; | |
| unsigned long discard_temp; | |
| unsigned int discard_index; | |
| unsigned int carry; | |
| __asm__ ( /* Shift element by element */ | |
| "\n1:\n\t" | |
| "lg %1, %O4(%0, %R4)\n\t" | |
| "risbg %3, %1, 0, 62, 1\n\t" | |
| "stg %3, %O4(%0, %R4)\n\t" | |
| "srlg %3, %1, 63\n\t" | |
| "la %0, 8(%0)\n\t" | |
| "brct %2, 1b\n\t" | |
| : "=&a" ( discard_offset ), | |
| "=&r" ( discard_temp ), | |
| "=&r" ( discard_index ), | |
| "=&r" ( carry ), | |
| "+S" ( *value ) | |
| : "0" ( 0UL ), | |
| "2" ( size ), | |
| "3" ( 0U ) | |
| : "cc" ); | |
| return carry; | |
| } | |
| /** | |
| * 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 )) int | |
| bigint_shr_raw ( unsigned long *value0, unsigned int size ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( void * ) value0 ); | |
| unsigned long discard_offset; | |
| unsigned long discard_temp; | |
| unsigned int carry; | |
| __asm__ ( /* Shift element by element */ | |
| "\n1:\n\t" | |
| "sllg %1, %2, 63\n\t" | |
| "lg %2, (%O3 - 8)(%0, %R3)\n\t" | |
| "risbg %1, %2, 1, 63, 63\n\t" | |
| "stg %1, (%O3 - 8)(%0, %R3)\n\t" | |
| "aghi %0, -8\n\t" | |
| "jnz 1b\n\t" | |
| : "=&a" ( discard_offset ), | |
| "=&r" ( discard_temp ), | |
| "=&r" ( carry ), | |
| "+S" ( *value ) | |
| : "0" ( sizeof ( *value ) ), | |
| "2" ( 0 ) | |
| : "cc" ); | |
| return ( carry & 1 ); | |
| } | |
| /** | |
| * Grow big integer | |
| * | |
| * @v source0 Element 0 of source big integer | |
| * @v source_size Number of elements in source big integer | |
| * @v dest0 Element 0 of destination big integer | |
| * @v dest_size Number of elements in destination big integer | |
| */ | |
| static inline __attribute__ (( always_inline )) void | |
| bigint_grow_raw ( const unsigned long *source0, unsigned int source_size, | |
| unsigned long *dest0, unsigned int dest_size ) { | |
| const bigint_t ( source_size ) __attribute__ (( may_alias )) *source = | |
| ( ( const void * ) source0 ); | |
| bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest = | |
| ( ( void * ) dest0 ); | |
| struct s390x_pointer_pair spair = { source, sizeof ( *source ) }; | |
| struct s390x_pointer_pair dpair = { dest, sizeof ( *dest ) }; | |
| __asm__ ( /* Copy source to destination, zero-padding as needed */ | |
| "\n1:\n\t" | |
| "mvcle %0, %1, 0\n\t" | |
| "jo 1b\n\t" | |
| : "+r" ( dpair ), "+r" ( spair ), "=m" ( *dest ) | |
| : "m" ( *source ) | |
| : "cc" ); | |
| } | |
| /** | |
| * Shrink big integer | |
| * | |
| * @v source0 Element 0 of source big integer | |
| * @v source_size Number of elements in source big integer | |
| * @v dest0 Element 0 of destination big integer | |
| * @v dest_size Number of elements in destination big integer | |
| */ | |
| static inline __attribute__ (( always_inline )) void | |
| bigint_shrink_raw ( const unsigned long *source0, unsigned int source_size, | |
| unsigned long *dest0, unsigned int dest_size ) { | |
| const bigint_t ( source_size ) __attribute__ (( may_alias )) *source = | |
| ( ( const void * ) source0 ); | |
| bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest = | |
| ( ( void * ) dest0 ); | |
| struct s390x_pointer_pair spair = { source, sizeof ( *source ) }; | |
| struct s390x_pointer_pair dpair = { dest, sizeof ( *dest ) }; | |
| __asm__ ( /* Copy source to destination, truncating if needed */ | |
| "\n1:\n\t" | |
| "mvcle %0, %1, 0\n\t" | |
| "jo 1b\n\t" | |
| : "+r" ( dpair ), "+r" ( spair ), "=m" ( *dest ) | |
| : "m" ( *source ) | |
| : "cc" ); | |
| } | |
| /** | |
| * 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 unsigned long multiplicand, | |
| const unsigned long multiplier, | |
| unsigned long *result, unsigned long *carry ) { | |
| struct s390x_scalar_pair pair; | |
| __asm__ ( /* Perform multiplication */ | |
| "lgr %N0, %3\n\t" | |
| "mlgr %0, %4\n\t" | |
| /* Add carry-in */ | |
| "algr %N0, %2\n\t" | |
| "slbgr %2, %2\n\t" | |
| "aghi %2, 1\n\t" | |
| /* Accumulate result */ | |
| "alg %N0, %1\n\t" | |
| "stg %N0, %1\n\t" | |
| /* Accumulate carry-out */ | |
| "alcgr %2, %0\n\t" | |
| : "=&r" ( pair ), | |
| "+T" ( *result ), | |
| "+r" ( *carry ) | |
| : "r" ( multiplicand ), | |
| "r" ( multiplier ) | |
| : "cc" ); | |
| } | |
| #endif /* _BITS_BIGINT_H */ |