jump_label.c 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019 Helge Deller <[email protected]>
  4. *
  5. * Based on arch/arm64/kernel/jump_label.c
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/jump_label.h>
  9. #include <linux/bug.h>
  10. #include <asm/alternative.h>
  11. #include <asm/patch.h>
  12. static inline int reassemble_17(int as17)
  13. {
  14. return (((as17 & 0x10000) >> 16) |
  15. ((as17 & 0x0f800) << 5) |
  16. ((as17 & 0x00400) >> 8) |
  17. ((as17 & 0x003ff) << 3));
  18. }
  19. void arch_jump_label_transform(struct jump_entry *entry,
  20. enum jump_label_type type)
  21. {
  22. void *addr = (void *)jump_entry_code(entry);
  23. u32 insn;
  24. if (type == JUMP_LABEL_JMP) {
  25. void *target = (void *)jump_entry_target(entry);
  26. int distance = target - addr;
  27. /*
  28. * Encode the PA1.1 "b,n" instruction with a 17-bit
  29. * displacement. In case we hit the BUG(), we could use
  30. * another branch instruction with a 22-bit displacement on
  31. * 64-bit CPUs instead. But this seems sufficient for now.
  32. */
  33. distance -= 8;
  34. BUG_ON(distance > 262143 || distance < -262144);
  35. insn = 0xe8000002 | reassemble_17(distance >> 2);
  36. } else {
  37. insn = INSN_NOP;
  38. }
  39. patch_text(addr, insn);
  40. }