jump_label.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * Jump label s390 support
  3. *
  4. * Copyright IBM Corp. 2011
  5. * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/uaccess.h>
  9. #include <linux/stop_machine.h>
  10. #include <linux/jump_label.h>
  11. #include <asm/ipl.h>
  12. #ifdef HAVE_JUMP_LABEL
  13. struct insn {
  14. u16 opcode;
  15. s32 offset;
  16. } __packed;
  17. struct insn_args {
  18. struct jump_entry *entry;
  19. enum jump_label_type type;
  20. };
  21. static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
  22. {
  23. /* brcl 0,0 */
  24. insn->opcode = 0xc004;
  25. insn->offset = 0;
  26. }
  27. static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
  28. {
  29. /* brcl 15,offset */
  30. insn->opcode = 0xc0f4;
  31. insn->offset = (entry->target - entry->code) >> 1;
  32. }
  33. static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
  34. struct insn *new)
  35. {
  36. unsigned char *ipc = (unsigned char *)entry->code;
  37. unsigned char *ipe = (unsigned char *)expected;
  38. unsigned char *ipn = (unsigned char *)new;
  39. pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
  40. pr_emerg("Found: %6ph\n", ipc);
  41. pr_emerg("Expected: %6ph\n", ipe);
  42. pr_emerg("New: %6ph\n", ipn);
  43. panic("Corrupted kernel text");
  44. }
  45. static struct insn orignop = {
  46. .opcode = 0xc004,
  47. .offset = JUMP_LABEL_NOP_OFFSET >> 1,
  48. };
  49. static void __jump_label_transform(struct jump_entry *entry,
  50. enum jump_label_type type,
  51. int init)
  52. {
  53. struct insn old, new;
  54. if (type == JUMP_LABEL_JMP) {
  55. jump_label_make_nop(entry, &old);
  56. jump_label_make_branch(entry, &new);
  57. } else {
  58. jump_label_make_branch(entry, &old);
  59. jump_label_make_nop(entry, &new);
  60. }
  61. if (init) {
  62. if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
  63. jump_label_bug(entry, &orignop, &new);
  64. } else {
  65. if (memcmp((void *)entry->code, &old, sizeof(old)))
  66. jump_label_bug(entry, &old, &new);
  67. }
  68. s390_kernel_write((void *)entry->code, &new, sizeof(new));
  69. }
  70. static int __sm_arch_jump_label_transform(void *data)
  71. {
  72. struct insn_args *args = data;
  73. __jump_label_transform(args->entry, args->type, 0);
  74. return 0;
  75. }
  76. void arch_jump_label_transform(struct jump_entry *entry,
  77. enum jump_label_type type)
  78. {
  79. struct insn_args args;
  80. args.entry = entry;
  81. args.type = type;
  82. stop_machine(__sm_arch_jump_label_transform, &args, NULL);
  83. }
  84. void arch_jump_label_transform_static(struct jump_entry *entry,
  85. enum jump_label_type type)
  86. {
  87. __jump_label_transform(entry, type, 1);
  88. }
  89. #endif