From: Heiko Carstens Date: Fri, 7 Feb 2025 14:48:56 +0000 (+0100) Subject: s390: Static branches for machine features infrastructure X-Git-Tag: v6.15-rc1~113^2~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7e81efc2436c553ca29eae5f069480de3d9f975;p=thirdparty%2Fkernel%2Flinux.git s390: Static branches for machine features infrastructure Provide infrastructure which allows to generate machine_has_() functions, which are replacing the existing MACHINE_HAS_ macros. Such function usages generate a static branch depending on . The static branch is patched using an alternative. Each correlates with a bit set in the machine_features bit field. If the corresponding bit is set, the branch will be patched. In order to have any effect on branch patching feature bits must be set with set_machine_features() in the decompressor before alternatives patching of the kernel image. It is possible to use clear_machine_feature() and test_machine_feature() for machine features which cannot be completely detected within the decompressor, e.g. if common code command line parameters allow to enable or disable certain features. In such cases test_machine_feature() instead of machine_has_feature() must be used within the kernel. This results in a runtime check and not a static branch. Reviewed-by: Vasily Gorbik Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h index 73e781b56bfe8..67abef07ac931 100644 --- a/arch/s390/include/asm/alternative.h +++ b/arch/s390/include/asm/alternative.h @@ -32,8 +32,9 @@ #define ALT_CTX_ALL (ALT_CTX_EARLY | ALT_CTX_LATE) #define ALT_TYPE_FACILITY 0 -#define ALT_TYPE_SPEC 1 -#define ALT_TYPE_LOWCORE 2 +#define ALT_TYPE_FEATURE 1 +#define ALT_TYPE_SPEC 2 +#define ALT_TYPE_LOWCORE 3 #define ALT_DATA_SHIFT 0 #define ALT_TYPE_SHIFT 20 @@ -43,6 +44,10 @@ ALT_TYPE_FACILITY << ALT_TYPE_SHIFT | \ (facility) << ALT_DATA_SHIFT) +#define ALT_FEATURE(feature) (ALT_CTX_EARLY << ALT_CTX_SHIFT | \ + ALT_TYPE_FEATURE << ALT_TYPE_SHIFT | \ + (feature) << ALT_DATA_SHIFT) + #define ALT_SPEC(facility) (ALT_CTX_LATE << ALT_CTX_SHIFT | \ ALT_TYPE_SPEC << ALT_TYPE_SHIFT | \ (facility) << ALT_DATA_SHIFT) diff --git a/arch/s390/include/asm/machine.h b/arch/s390/include/asm/machine.h new file mode 100644 index 0000000000000..bbe6c24bfc883 --- /dev/null +++ b/arch/s390/include/asm/machine.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright IBM Corp. 2024 + */ + +#ifndef __ASM_S390_MACHINE_H +#define __ASM_S390_MACHINE_H + +#ifndef __ASSEMBLY__ + +#include +#include + +extern unsigned long machine_features[1]; + +#define MAX_MFEATURE_BIT (sizeof(machine_features) * BITS_PER_BYTE) + +static inline void __set_machine_feature(unsigned int nr, unsigned long *mfeatures) +{ + if (nr >= MAX_MFEATURE_BIT) + return; + __set_bit(nr, mfeatures); +} + +static inline void set_machine_feature(unsigned int nr) +{ + __set_machine_feature(nr, machine_features); +} + +static inline void __clear_machine_feature(unsigned int nr, unsigned long *mfeatures) +{ + if (nr >= MAX_MFEATURE_BIT) + return; + __clear_bit(nr, mfeatures); +} + +static inline void clear_machine_feature(unsigned int nr) +{ + __clear_machine_feature(nr, machine_features); +} + +static bool __test_machine_feature(unsigned int nr, unsigned long *mfeatures) +{ + if (nr >= MAX_MFEATURE_BIT) + return false; + return test_bit(nr, mfeatures); +} + +static bool test_machine_feature(unsigned int nr) +{ + return __test_machine_feature(nr, machine_features); +} + +static __always_inline bool __test_machine_feature_constant(unsigned int nr) +{ + asm goto( + ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FEATURE(%[nr])) + : + : [nr] "i" (nr) + : + : l_no); + return true; +l_no: + return false; +} + +#define DEFINE_MACHINE_HAS_FEATURE(name, feature) \ +static __always_inline bool machine_has_##name(void) \ +{ \ + if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(feature)) \ + return __test_machine_feature_constant(feature); \ + return test_machine_feature(feature); \ +} + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_S390_MACHINE_H */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 8d5d0de35de05..d3839fc0543dc 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -5,6 +5,10 @@ #include #include #include +#include +#include + +unsigned long __bootdata_preserved(machine_features[1]); void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx) { @@ -23,6 +27,9 @@ void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsign case ALT_TYPE_FACILITY: replace = test_facility(a->data); break; + case ALT_TYPE_FEATURE: + replace = test_machine_feature(a->data); + break; case ALT_TYPE_SPEC: replace = nobp_enabled(); break;