18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_S390_ALTERNATIVE_H 38c2ecf20Sopenharmony_ci#define _ASM_S390_ALTERNATIVE_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/stddef.h> 98c2ecf20Sopenharmony_ci#include <linux/stringify.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct alt_instr { 128c2ecf20Sopenharmony_ci s32 instr_offset; /* original instruction */ 138c2ecf20Sopenharmony_ci s32 repl_offset; /* offset to replacement instruction */ 148c2ecf20Sopenharmony_ci u16 facility; /* facility bit set for replacement */ 158c2ecf20Sopenharmony_ci u8 instrlen; /* length of original instruction */ 168c2ecf20Sopenharmony_ci u8 replacementlen; /* length of new instruction */ 178c2ecf20Sopenharmony_ci} __packed; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_civoid apply_alternative_instructions(void); 208c2ecf20Sopenharmony_civoid apply_alternatives(struct alt_instr *start, struct alt_instr *end); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * |661: |662: |6620 |663: 248c2ecf20Sopenharmony_ci * +-----------+---------------------+ 258c2ecf20Sopenharmony_ci * | oldinstr | oldinstr_padding | 268c2ecf20Sopenharmony_ci * | +----------+----------+ 278c2ecf20Sopenharmony_ci * | | | | 288c2ecf20Sopenharmony_ci * | | >6 bytes |6/4/2 nops| 298c2ecf20Sopenharmony_ci * | |6 bytes jg-----------> 308c2ecf20Sopenharmony_ci * +-----------+---------------------+ 318c2ecf20Sopenharmony_ci * ^^ static padding ^^ 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * .altinstr_replacement section 348c2ecf20Sopenharmony_ci * +---------------------+-----------+ 358c2ecf20Sopenharmony_ci * |6641: |6651: 368c2ecf20Sopenharmony_ci * | alternative instr 1 | 378c2ecf20Sopenharmony_ci * +-----------+---------+- - - - - -+ 388c2ecf20Sopenharmony_ci * |6642: |6652: | 398c2ecf20Sopenharmony_ci * | alternative instr 2 | padding 408c2ecf20Sopenharmony_ci * +---------------------+- - - - - -+ 418c2ecf20Sopenharmony_ci * ^ runtime ^ 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * .altinstructions section 448c2ecf20Sopenharmony_ci * +---------------------------------+ 458c2ecf20Sopenharmony_ci * | alt_instr entries for each | 468c2ecf20Sopenharmony_ci * | alternative instr | 478c2ecf20Sopenharmony_ci * +---------------------------------+ 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define b_altinstr(num) "664"#num 518c2ecf20Sopenharmony_ci#define e_altinstr(num) "665"#num 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define e_oldinstr_pad_end "663" 548c2ecf20Sopenharmony_ci#define oldinstr_len "662b-661b" 558c2ecf20Sopenharmony_ci#define oldinstr_total_len e_oldinstr_pad_end"b-661b" 568c2ecf20Sopenharmony_ci#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b" 578c2ecf20Sopenharmony_ci#define oldinstr_pad_len(num) \ 588c2ecf20Sopenharmony_ci "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \ 598c2ecf20Sopenharmony_ci "((" altinstr_len(num) ")-(" oldinstr_len "))" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define INSTR_LEN_SANITY_CHECK(len) \ 628c2ecf20Sopenharmony_ci ".if " len " > 254\n" \ 638c2ecf20Sopenharmony_ci "\t.error \"cpu alternatives does not support instructions " \ 648c2ecf20Sopenharmony_ci "blocks > 254 bytes\"\n" \ 658c2ecf20Sopenharmony_ci ".endif\n" \ 668c2ecf20Sopenharmony_ci ".if (" len ") %% 2\n" \ 678c2ecf20Sopenharmony_ci "\t.error \"cpu alternatives instructions length is odd\"\n" \ 688c2ecf20Sopenharmony_ci ".endif\n" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define OLDINSTR_PADDING(oldinstr, num) \ 718c2ecf20Sopenharmony_ci ".if " oldinstr_pad_len(num) " > 6\n" \ 728c2ecf20Sopenharmony_ci "\tjg " e_oldinstr_pad_end "f\n" \ 738c2ecf20Sopenharmony_ci "6620:\n" \ 748c2ecf20Sopenharmony_ci "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \ 758c2ecf20Sopenharmony_ci ".else\n" \ 768c2ecf20Sopenharmony_ci "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \ 778c2ecf20Sopenharmony_ci "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \ 788c2ecf20Sopenharmony_ci "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \ 798c2ecf20Sopenharmony_ci ".endif\n" 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define OLDINSTR(oldinstr, num) \ 828c2ecf20Sopenharmony_ci "661:\n\t" oldinstr "\n662:\n" \ 838c2ecf20Sopenharmony_ci OLDINSTR_PADDING(oldinstr, num) \ 848c2ecf20Sopenharmony_ci e_oldinstr_pad_end ":\n" \ 858c2ecf20Sopenharmony_ci INSTR_LEN_SANITY_CHECK(oldinstr_len) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define OLDINSTR_2(oldinstr, num1, num2) \ 888c2ecf20Sopenharmony_ci "661:\n\t" oldinstr "\n662:\n" \ 898c2ecf20Sopenharmony_ci ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n" \ 908c2ecf20Sopenharmony_ci OLDINSTR_PADDING(oldinstr, num2) \ 918c2ecf20Sopenharmony_ci ".else\n" \ 928c2ecf20Sopenharmony_ci OLDINSTR_PADDING(oldinstr, num1) \ 938c2ecf20Sopenharmony_ci ".endif\n" \ 948c2ecf20Sopenharmony_ci e_oldinstr_pad_end ":\n" \ 958c2ecf20Sopenharmony_ci INSTR_LEN_SANITY_CHECK(oldinstr_len) 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#define ALTINSTR_ENTRY(facility, num) \ 988c2ecf20Sopenharmony_ci "\t.long 661b - .\n" /* old instruction */ \ 998c2ecf20Sopenharmony_ci "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \ 1008c2ecf20Sopenharmony_ci "\t.word " __stringify(facility) "\n" /* facility bit */ \ 1018c2ecf20Sopenharmony_ci "\t.byte " oldinstr_total_len "\n" /* source len */ \ 1028c2ecf20Sopenharmony_ci "\t.byte " altinstr_len(num) "\n" /* alt instruction len */ 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \ 1058c2ecf20Sopenharmony_ci b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \ 1068c2ecf20Sopenharmony_ci INSTR_LEN_SANITY_CHECK(altinstr_len(num)) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* alternative assembly primitive: */ 1098c2ecf20Sopenharmony_ci#define ALTERNATIVE(oldinstr, altinstr, facility) \ 1108c2ecf20Sopenharmony_ci ".pushsection .altinstr_replacement, \"ax\"\n" \ 1118c2ecf20Sopenharmony_ci ALTINSTR_REPLACEMENT(altinstr, 1) \ 1128c2ecf20Sopenharmony_ci ".popsection\n" \ 1138c2ecf20Sopenharmony_ci OLDINSTR(oldinstr, 1) \ 1148c2ecf20Sopenharmony_ci ".pushsection .altinstructions,\"a\"\n" \ 1158c2ecf20Sopenharmony_ci ALTINSTR_ENTRY(facility, 1) \ 1168c2ecf20Sopenharmony_ci ".popsection\n" 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\ 1198c2ecf20Sopenharmony_ci ".pushsection .altinstr_replacement, \"ax\"\n" \ 1208c2ecf20Sopenharmony_ci ALTINSTR_REPLACEMENT(altinstr1, 1) \ 1218c2ecf20Sopenharmony_ci ALTINSTR_REPLACEMENT(altinstr2, 2) \ 1228c2ecf20Sopenharmony_ci ".popsection\n" \ 1238c2ecf20Sopenharmony_ci OLDINSTR_2(oldinstr, 1, 2) \ 1248c2ecf20Sopenharmony_ci ".pushsection .altinstructions,\"a\"\n" \ 1258c2ecf20Sopenharmony_ci ALTINSTR_ENTRY(facility1, 1) \ 1268c2ecf20Sopenharmony_ci ALTINSTR_ENTRY(facility2, 2) \ 1278c2ecf20Sopenharmony_ci ".popsection\n" 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * Alternative instructions for different CPU types or capabilities. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * This allows to use optimized instructions even on generic binary 1338c2ecf20Sopenharmony_ci * kernels. 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * oldinstr is padded with jump and nops at compile time if altinstr is 1368c2ecf20Sopenharmony_ci * longer. altinstr is padded with jump and nops at run-time during patching. 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * For non barrier like inlines please define new variants 1398c2ecf20Sopenharmony_ci * without volatile and memory clobber. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci#define alternative(oldinstr, altinstr, facility) \ 1428c2ecf20Sopenharmony_ci asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory") 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ 1458c2ecf20Sopenharmony_ci asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \ 1468c2ecf20Sopenharmony_ci altinstr2, facility2) ::: "memory") 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#endif /* _ASM_S390_ALTERNATIVE_H */ 151