From aa105c2dc06275dc9832a61a5a215bd6f0945106 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 13 Jun 2026 16:27:26 +0100 Subject: [PATCH] [s390x] Add support for the IBM s390x CPU architecture Add support for building iPXE as a 64-bit s390x binary for the Linux userspace platform. For example: make CROSS=s390x-linux-gnu- bin-s390x-linux/tests.linux Signed-off-by: Michael Brown --- src/arch/s390x/Makefile | 29 +++ src/arch/s390x/Makefile.linux | 6 + src/arch/s390x/core/s390x_string.c | 56 +++++ src/arch/s390x/core/setjmp.S | 61 +++++ src/arch/s390x/include/bits/bigint.h | 250 +++++++++++++++++++++ src/arch/s390x/include/bits/bitops.h | 83 +++++++ src/arch/s390x/include/bits/byteswap.h | 62 +++++ src/arch/s390x/include/bits/compiler.h | 38 ++++ src/arch/s390x/include/bits/endian.h | 8 + src/arch/s390x/include/bits/errfile.h | 19 ++ src/arch/s390x/include/bits/io.h | 15 ++ src/arch/s390x/include/bits/profile.h | 28 +++ src/arch/s390x/include/bits/setjmp.h | 12 + src/arch/s390x/include/bits/stdint.h | 23 ++ src/arch/s390x/include/bits/string.h | 108 +++++++++ src/arch/s390x/include/bits/strings.h | 66 ++++++ src/arch/s390x/include/ipxe/efi/dhcparch.h | 20 ++ 17 files changed, 884 insertions(+) create mode 100644 src/arch/s390x/Makefile create mode 100644 src/arch/s390x/Makefile.linux create mode 100644 src/arch/s390x/core/s390x_string.c create mode 100644 src/arch/s390x/core/setjmp.S create mode 100644 src/arch/s390x/include/bits/bigint.h create mode 100644 src/arch/s390x/include/bits/bitops.h create mode 100644 src/arch/s390x/include/bits/byteswap.h create mode 100644 src/arch/s390x/include/bits/compiler.h create mode 100644 src/arch/s390x/include/bits/endian.h create mode 100644 src/arch/s390x/include/bits/errfile.h create mode 100644 src/arch/s390x/include/bits/io.h create mode 100644 src/arch/s390x/include/bits/profile.h create mode 100644 src/arch/s390x/include/bits/setjmp.h create mode 100644 src/arch/s390x/include/bits/stdint.h create mode 100644 src/arch/s390x/include/bits/string.h create mode 100644 src/arch/s390x/include/bits/strings.h create mode 100644 src/arch/s390x/include/ipxe/efi/dhcparch.h diff --git a/src/arch/s390x/Makefile b/src/arch/s390x/Makefile new file mode 100644 index 000000000..63f9246a8 --- /dev/null +++ b/src/arch/s390x/Makefile @@ -0,0 +1,29 @@ +# Specify compressor +# +ZBIN = $(ZBIN64) + +# Assembler section type character +# +ASM_TCHAR := @ +ASM_TCHAR_OPS := @ + +# S/390-specific flags +# +CFLAGS += -mno-backchain -mpacked-stack -msoft-float + +# EFI requires -fshort-wchar, and nothing else currently uses wchar_t +# +CFLAGS += -fshort-wchar + +# Include S/390-specific headers +# +INCDIRS := arch/$(ARCH)/include $(INCDIRS) + +# S/390-specific directories containing source files +# +SRCDIRS += arch/s390x/core + +# Include platform-specific Makefile +# +MAKEDEPS += arch/s390x/Makefile.$(PLATFORM) +include arch/s390x/Makefile.$(PLATFORM) diff --git a/src/arch/s390x/Makefile.linux b/src/arch/s390x/Makefile.linux new file mode 100644 index 000000000..42590441e --- /dev/null +++ b/src/arch/s390x/Makefile.linux @@ -0,0 +1,6 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Include generic Linux Makefile +# +MAKEDEPS += Makefile.linux +include Makefile.linux diff --git a/src/arch/s390x/core/s390x_string.c b/src/arch/s390x/core/s390x_string.c new file mode 100644 index 000000000..71721e0e4 --- /dev/null +++ b/src/arch/s390x/core/s390x_string.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * 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 + * + * Optimised string operations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** + * Copy (possibly overlapping) memory region + * + * @v dest Destination region + * @v src Source region + * @v len Length + */ +void s390x_memmove ( void *dest, const void *src, size_t len ) { + const uint8_t *src_bytes = ( src + len ); + uint8_t *dest_bytes = ( dest + len ); + + /* Use memcpy() if copy direction is forwards */ + if ( dest <= src ) { + memcpy ( dest, src, len ); + return; + } + + /* Assume memmove() is not performance-critical, and perform a + * bytewise copy backwards for simplicity. + */ + while ( len-- ) + *(--dest_bytes) = *(--src_bytes); +} diff --git a/src/arch/s390x/core/setjmp.S b/src/arch/s390x/core/setjmp.S new file mode 100644 index 000000000..c80757c5b --- /dev/null +++ b/src/arch/s390x/core/setjmp.S @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * 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 + * + * Long jumps + * + */ + + .section ".note.GNU-stack", "", @progbits + .text + +/* + * Save stack context for non-local goto + */ + .section ".text.setjmp", "ax", @progbits + .globl setjmp +setjmp: + /* Save registers */ + stmg %r6, %r15, 0(%r2) + /* Return zero when returning as setjmp() */ + lghi %r2, 0 + br %r14 + .size setjmp, . - setjmp + +/* + * Non-local jump to a saved stack context + */ + .section ".text.longjmp", "ax", @progbits + .globl longjmp +longjmp: + /* Restore registers */ + lmg %r6, %r15, 0(%r2) + /* Force result to non-zero */ + ltgr %r2, %r3 + lochiz %r2, 1 + /* Return to setjmp() caller */ + br %r14 + .size longjmp, . - longjmp diff --git a/src/arch/s390x/include/bits/bigint.h b/src/arch/s390x/include/bits/bigint.h new file mode 100644 index 000000000..83a0923cf --- /dev/null +++ b/src/arch/s390x/include/bits/bigint.h @@ -0,0 +1,250 @@ +#ifndef _BITS_BIGINT_H +#define _BITS_BIGINT_H + +/** @file + * + * Big integer support + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** 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 ) ); + + 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 ) ); + + 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 ) ); + + 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 ) ); + + 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 ) ); +} + +/** + * 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 ) ); +} + +/** + * 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 ) ); +} + +#endif /* _BITS_BIGINT_H */ diff --git a/src/arch/s390x/include/bits/bitops.h b/src/arch/s390x/include/bits/bitops.h new file mode 100644 index 000000000..2065ddbb8 --- /dev/null +++ b/src/arch/s390x/include/bits/bitops.h @@ -0,0 +1,83 @@ +#ifndef _BITS_BITOPS_H +#define _BITS_BITOPS_H + +/** @file + * + * S/390 bit operations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** + * Test and set bit atomically + * + * @v bit Bit to set + * @v bits Bit field + * @ret old Old value of bit (zero or non-zero) + */ +static inline __attribute__ (( always_inline )) int +test_and_set_bit ( unsigned int bit, volatile void *bits ) { + unsigned int index = ( bit / 32 ); + unsigned int offset = ( bit % 32 ); + volatile uint32_t *word = ( ( ( volatile uint32_t * ) bits ) + index ); + uint32_t mask = cpu_to_le32 ( 1U << offset ); + uint32_t old; + + __asm__ __volatile__ ( "lao %0, %2, %1" + : "=r" ( old ), "+S" ( *word ) + : "r" ( mask ) ); + + return ( !! ( old & mask ) ); +} + +/** + * Test and clear bit atomically + * + * @v bit Bit to set + * @v bits Bit field + * @ret old Old value of bit (zero or non-zero) + */ +static inline __attribute__ (( always_inline )) int +test_and_clear_bit ( unsigned int bit, volatile void *bits ) { + unsigned int index = ( bit / 32 ); + unsigned int offset = ( bit % 32 ); + volatile uint32_t *word = ( ( ( volatile uint32_t * ) bits ) + index ); + uint32_t mask = cpu_to_le32 ( 1U << offset ); + uint32_t old; + + __asm__ __volatile__ ( "lan %0, %2, %1" + : "=r" ( old ), "+S" ( *word ) + : "r" ( ~mask ) ); + + return ( !! ( old & mask ) ); +} + +/** + * Set bit atomically + * + * @v bit Bit to set + * @v bits Bit field + */ +static inline __attribute__ (( always_inline )) void +set_bit ( unsigned int bit, volatile void *bits ) { + + test_and_set_bit ( bit, bits ); +} + +/** + * Clear bit atomically + * + * @v bit Bit to set + * @v bits Bit field + */ +static inline __attribute__ (( always_inline )) void +clear_bit ( unsigned int bit, volatile void *bits ) { + + test_and_clear_bit ( bit, bits ); +} + +#endif /* _BITS_BITOPS_H */ diff --git a/src/arch/s390x/include/bits/byteswap.h b/src/arch/s390x/include/bits/byteswap.h new file mode 100644 index 000000000..293fe3b9d --- /dev/null +++ b/src/arch/s390x/include/bits/byteswap.h @@ -0,0 +1,62 @@ +#ifndef _BITS_BYTESWAP_H +#define _BITS_BYTESWAP_H + +/** @file + * + * Byte-order swapping functions + * + */ + +#include + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +static inline __attribute__ (( always_inline, const )) uint16_t +__bswap_variable_16 ( uint16_t x ) { + unsigned int swapped; + + __asm__ ( "lrvr %0, %1" : "=r" ( swapped ) : "r" ( x ) ); + return ( swapped >> 16 ); +} + +static inline __attribute__ (( always_inline )) void +__bswap_16s ( uint16_t *x ) { + unsigned int swapped; + + __asm__ ( "lrvh %0, %1" : "=r" ( swapped ) : "T" ( *x ) ); + *x = swapped; +} + +static inline __attribute__ (( always_inline, const )) uint32_t +__bswap_variable_32 ( uint32_t x ) { + unsigned int swapped; + + __asm__ ( "lrvr %0, %1" : "=r" ( swapped ) : "r" ( x ) ); + return swapped; +} + +static inline __attribute__ (( always_inline )) void +__bswap_32s ( uint32_t *x ) { + unsigned int swapped; + + __asm__ ( "lrv %0, %1" : "=r" ( swapped ) : "T" ( *x ) ); + *x = swapped; +} + +static inline __attribute__ (( always_inline, const )) uint64_t +__bswap_variable_64 ( uint64_t x ) { + unsigned long swapped; + + __asm__ ( "lrvgr %0, %1" : "=r" ( swapped ) : "r" ( x ) ); + return swapped; +} + +static inline __attribute__ (( always_inline )) void +__bswap_64s ( uint64_t *x ) { + unsigned long swapped; + + __asm__ ( "lrvg %0, %1" : "=r" ( swapped ) : "T" ( *x ) ); + *x = swapped; +} + +#endif /* _BITS_BYTESWAP_H */ diff --git a/src/arch/s390x/include/bits/compiler.h b/src/arch/s390x/include/bits/compiler.h new file mode 100644 index 000000000..b14a8da68 --- /dev/null +++ b/src/arch/s390x/include/bits/compiler.h @@ -0,0 +1,38 @@ +#ifndef _BITS_COMPILER_H +#define _BITS_COMPILER_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** Dummy relocation type */ +#define RELOC_TYPE_NONE R_390_NONE + +#ifndef ASSEMBLY + +/** Unprefixed constant operand modifier */ +#define ASM_NO_PREFIX "c" + +/** Declare a function with standard calling conventions */ +#define __asmcall + +/** Declare a function with libgcc implicit linkage */ +#define __libgcc + +/** An even/odd register pair for scalar values */ +struct s390x_scalar_pair { + /** Scalar value in even 64-bit register */ + unsigned long even; + /** Scalar value in odd 64-bit register */ + unsigned long odd; +}; + +/** An even/odd register pair for pointer and length values */ +struct s390x_pointer_pair { + /** Pointer value in even 64-bit register */ + const void *even; + /** Length value in odd 64-bit register */ + unsigned long odd; +}; + +#endif /* ASSEMBLY */ + +#endif /* _BITS_COMPILER_H */ diff --git a/src/arch/s390x/include/bits/endian.h b/src/arch/s390x/include/bits/endian.h new file mode 100644 index 000000000..ab1787918 --- /dev/null +++ b/src/arch/s390x/include/bits/endian.h @@ -0,0 +1,8 @@ +#ifndef _BITS_ENDIAN_H +#define _BITS_ENDIAN_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#define __BYTE_ORDER __BIG_ENDIAN + +#endif /* _BITS_ENDIAN_H */ diff --git a/src/arch/s390x/include/bits/errfile.h b/src/arch/s390x/include/bits/errfile.h new file mode 100644 index 000000000..4f47194d0 --- /dev/null +++ b/src/arch/s390x/include/bits/errfile.h @@ -0,0 +1,19 @@ +#ifndef _BITS_ERRFILE_H +#define _BITS_ERRFILE_H + +/** @file + * + * S/390 error file identifiers + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @addtogroup errfile Error file identifiers + * @{ + */ + +/** @} */ + +#endif /* _BITS_ERRFILE_H */ diff --git a/src/arch/s390x/include/bits/io.h b/src/arch/s390x/include/bits/io.h new file mode 100644 index 000000000..5845e7bd5 --- /dev/null +++ b/src/arch/s390x/include/bits/io.h @@ -0,0 +1,15 @@ +#ifndef _BITS_IO_H +#define _BITS_IO_H + +/** @file + * + * S/390-specific I/O API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** Page shift */ +#define PAGE_SHIFT 12 + +#endif /* _BITS_IO_H */ diff --git a/src/arch/s390x/include/bits/profile.h b/src/arch/s390x/include/bits/profile.h new file mode 100644 index 000000000..b67934360 --- /dev/null +++ b/src/arch/s390x/include/bits/profile.h @@ -0,0 +1,28 @@ +#ifndef _BITS_PROFILE_H +#define _BITS_PROFILE_H + +/** @file + * + * Profiling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** + * Get profiling timestamp + * + * @ret timestamp Timestamp + */ +static inline __attribute__ (( always_inline )) unsigned long +profile_timestamp ( void ) { + uint64_t cycles; + + /* Read timestamp counter */ + __asm__ ( "stckf %0" : "=Q" ( cycles ) ); + return cycles; +} + +#endif /* _BITS_PROFILE_H */ diff --git a/src/arch/s390x/include/bits/setjmp.h b/src/arch/s390x/include/bits/setjmp.h new file mode 100644 index 000000000..80c872e6c --- /dev/null +++ b/src/arch/s390x/include/bits/setjmp.h @@ -0,0 +1,12 @@ +#ifndef _BITS_SETJMP_H +#define _BITS_SETJMP_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** A jump buffer */ +typedef struct { + /** Callee-saved registers (r6-r15) */ + unsigned long regs[12]; +} jmp_buf[1]; + +#endif /* _BITS_SETJMP_H */ diff --git a/src/arch/s390x/include/bits/stdint.h b/src/arch/s390x/include/bits/stdint.h new file mode 100644 index 000000000..fe1f9946a --- /dev/null +++ b/src/arch/s390x/include/bits/stdint.h @@ -0,0 +1,23 @@ +#ifndef _BITS_STDINT_H +#define _BITS_STDINT_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +typedef __SIZE_TYPE__ size_t; +typedef signed long ssize_t; +typedef signed long off_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef unsigned long physaddr_t; +typedef unsigned long intptr_t; + +#endif /* _BITS_STDINT_H */ diff --git a/src/arch/s390x/include/bits/string.h b/src/arch/s390x/include/bits/string.h new file mode 100644 index 000000000..c971cdaad --- /dev/null +++ b/src/arch/s390x/include/bits/string.h @@ -0,0 +1,108 @@ +#ifndef _BITS_STRING_H +#define _BITS_STRING_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * String functions + * + */ + +#include + +extern void s390x_memmove ( void *dest, const void *src, size_t len ); + +/** + * Fill memory region + * + * @v dest Destination region + * @v character Fill character + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memset ( void *dest, int character, size_t len ) { + const struct s390x_pointer_pair spair = { NULL, 0 }; + struct s390x_pointer_pair dpair = { dest, len }; + char ( * dmem ) [ len ] = dest; + + if ( __builtin_constant_p ( character ) ) { + /* Constant fill character: use an immediate */ + __asm__ ( "\n1:\n\t" + "mvcle %0, %2, %3\n\t" + "jo 1b\n\t" + : "+r" ( dpair ), "=m" ( *dmem ) + : "r" ( spair ), "i" ( character ) ); + } else { + /* Variable fill character: use a register */ + __asm__ ( "\n1:\n\t" + "mvcle %0, %2, 0(%3)\n\t" + "jo 1b\n\t" + : "+r" ( dpair ), "=m" ( *dmem ) + : "r" ( spair ), "a" ( character ) ); + } + + return dest; +} + +/** + * Copy memory region + * + * @v dest Destination region + * @v src Source region + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memcpy ( void *dest, const void *src, size_t len ) { + struct s390x_pointer_pair spair = { src, len }; + struct s390x_pointer_pair dpair = { dest, len }; + const char ( * smem ) [ len ] = src; + char ( * dmem ) [ len ] = dest; + + if ( __builtin_constant_p ( len ) && ( len == 0 ) ) { + /* Constant zero length: do nothing */ + } else if ( __builtin_constant_p ( len ) && ( len <= 256 ) ) { + /* Constant small non-zero length: use "mvc" */ + __asm__ ( "mvc %O0(%2,%R0), %1" + : "=Q" ( *dmem ) + : "Q" ( *smem ), "i" ( len ) ); + } else { + /* Variable or large length: use "mvcle" */ + __asm__ ( "\n1:\n\t" + "mvcle %0, %1, 0\n\t" + "jo 1b\n\t" + : "+r" ( dpair ), "+r" ( spair ), "=m" ( *dmem ) + : "m" ( *smem ) ); + } + + return dest; +} + +/** + * Copy (possibly overlapping) memory region + * + * @v dest Destination region + * @v src Source region + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memmove ( void *dest, const void *src, size_t len ) { + ssize_t offset = ( dest - src ); + + /* If direction of copy is known to be forwards at build time, + * then use standard memcpy(). + */ + if ( __builtin_constant_p ( offset ) && ( offset <= 0 ) ) { + memcpy ( dest, src, len ); + return dest; + } + + /* Otherwise, use ambidirectional copy */ + s390x_memmove ( dest, src, len ); + return dest; +} + +#endif /* _BITS_STRING_H */ diff --git a/src/arch/s390x/include/bits/strings.h b/src/arch/s390x/include/bits/strings.h new file mode 100644 index 000000000..6fbe0e88c --- /dev/null +++ b/src/arch/s390x/include/bits/strings.h @@ -0,0 +1,66 @@ +#ifndef _BITS_STRINGS_H +#define _BITS_STRINGS_H + +/** @file + * + * String functions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * Find first (i.e. least significant) set bit + * + * @v value Value + * @ret lsb Least significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){ + struct s390x_scalar_pair pair; + + /* Extract least significant set bit */ + value &= -value; + + /* Count number of leading zeros before LSB */ + __asm__ ( "flogr %0, %1" : "=r" ( pair ) : "r" ( value ) ); + + return ( 64 - pair.even ); +} + +/** + * Find first (i.e. least significant) set bit + * + * @v value Value + * @ret lsb Least significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __ffsl ( long value ) { + + return __ffsll ( value ); +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsll ( long long value ){ + struct s390x_scalar_pair pair; + + /* Count leading zeros */ + __asm__ ( "flogr %0, %1" : "=r" ( pair ) : "r" ( value ) ); + return ( 64 - pair.even ); +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsl ( long value ) { + + return __flsll ( value ); +} + +#endif /* _BITS_STRINGS_H */ diff --git a/src/arch/s390x/include/ipxe/efi/dhcparch.h b/src/arch/s390x/include/ipxe/efi/dhcparch.h new file mode 100644 index 000000000..7de8e01ee --- /dev/null +++ b/src/arch/s390x/include/ipxe/efi/dhcparch.h @@ -0,0 +1,20 @@ +#ifndef _IPXE_EFI_DHCPARCH_H +#define _IPXE_EFI_DHCPARCH_H + +/** @file + * + * DHCP client architecture definitions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** DHCP client architecture */ +#define DHCP_ARCH_CLIENT_ARCHITECTURE 0xffff /* Not assigned */ + +/** DHCP client network device interface */ +#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */ + +#endif /* _IPXE_EFI_DHCPARCH_H */