root/arch/s390/kernel/alternative.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. disable_alternative_instructions
  2. add_jump_padding
  3. add_padding
  4. __apply_alternatives
  5. apply_alternatives
  6. apply_alternative_instructions

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/module.h>
   3 #include <asm/alternative.h>
   4 #include <asm/facility.h>
   5 #include <asm/nospec-branch.h>
   6 
   7 #define MAX_PATCH_LEN (255 - 1)
   8 
   9 static int __initdata_or_module alt_instr_disabled;
  10 
  11 static int __init disable_alternative_instructions(char *str)
  12 {
  13         alt_instr_disabled = 1;
  14         return 0;
  15 }
  16 
  17 early_param("noaltinstr", disable_alternative_instructions);
  18 
  19 struct brcl_insn {
  20         u16 opc;
  21         s32 disp;
  22 } __packed;
  23 
  24 static u16 __initdata_or_module nop16 = 0x0700;
  25 static u32 __initdata_or_module nop32 = 0x47000000;
  26 static struct brcl_insn __initdata_or_module nop48 = {
  27         0xc004, 0
  28 };
  29 
  30 static const void *nops[] __initdata_or_module = {
  31         &nop16,
  32         &nop32,
  33         &nop48
  34 };
  35 
  36 static void __init_or_module add_jump_padding(void *insns, unsigned int len)
  37 {
  38         struct brcl_insn brcl = {
  39                 0xc0f4,
  40                 len / 2
  41         };
  42 
  43         memcpy(insns, &brcl, sizeof(brcl));
  44         insns += sizeof(brcl);
  45         len -= sizeof(brcl);
  46 
  47         while (len > 0) {
  48                 memcpy(insns, &nop16, 2);
  49                 insns += 2;
  50                 len -= 2;
  51         }
  52 }
  53 
  54 static void __init_or_module add_padding(void *insns, unsigned int len)
  55 {
  56         if (len > 6)
  57                 add_jump_padding(insns, len);
  58         else if (len >= 2)
  59                 memcpy(insns, nops[len / 2 - 1], len);
  60 }
  61 
  62 static void __init_or_module __apply_alternatives(struct alt_instr *start,
  63                                                   struct alt_instr *end)
  64 {
  65         struct alt_instr *a;
  66         u8 *instr, *replacement;
  67         u8 insnbuf[MAX_PATCH_LEN];
  68 
  69         /*
  70          * The scan order should be from start to end. A later scanned
  71          * alternative code can overwrite previously scanned alternative code.
  72          */
  73         for (a = start; a < end; a++) {
  74                 int insnbuf_sz = 0;
  75 
  76                 instr = (u8 *)&a->instr_offset + a->instr_offset;
  77                 replacement = (u8 *)&a->repl_offset + a->repl_offset;
  78 
  79                 if (!__test_facility(a->facility,
  80                                      S390_lowcore.alt_stfle_fac_list))
  81                         continue;
  82 
  83                 if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
  84                         WARN_ONCE(1, "cpu alternatives instructions length is "
  85                                      "odd, skipping patching\n");
  86                         continue;
  87                 }
  88 
  89                 memcpy(insnbuf, replacement, a->replacementlen);
  90                 insnbuf_sz = a->replacementlen;
  91 
  92                 if (a->instrlen > a->replacementlen) {
  93                         add_padding(insnbuf + a->replacementlen,
  94                                     a->instrlen - a->replacementlen);
  95                         insnbuf_sz += a->instrlen - a->replacementlen;
  96                 }
  97 
  98                 s390_kernel_write(instr, insnbuf, insnbuf_sz);
  99         }
 100 }
 101 
 102 void __init_or_module apply_alternatives(struct alt_instr *start,
 103                                          struct alt_instr *end)
 104 {
 105         if (!alt_instr_disabled)
 106                 __apply_alternatives(start, end);
 107 }
 108 
 109 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 110 void __init apply_alternative_instructions(void)
 111 {
 112         apply_alternatives(__alt_instructions, __alt_instructions_end);
 113 }

/* [<][>][^][v][top][bottom][index][help] */