jump_label.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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: %02x %02x %02x %02x %02x %02x\n",
  41. ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
  42. pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
  43. ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
  44. pr_emerg("New: %02x %02x %02x %02x %02x %02x\n",
  45. ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]);
  46. panic("Corrupted kernel text");
  47. }
  48. static struct insn orignop = {
  49. .opcode = 0xc004,
  50. .offset = JUMP_LABEL_NOP_OFFSET >> 1,
  51. };
  52. static void __jump_label_transform(struct jump_entry *entry,
  53. enum jump_label_type type,
  54. int init)
  55. {
  56. struct insn old, new;
  57. if (type == JUMP_LABEL_ENABLE) {
  58. jump_label_make_nop(entry, &old);
  59. jump_label_make_branch(entry, &new);
  60. } else {
  61. jump_label_make_branch(entry, &old);
  62. jump_label_make_nop(entry, &new);
  63. }
  64. if (init) {
  65. if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
  66. jump_label_bug(entry, &orignop, &new);
  67. } else {
  68. if (memcmp((void *)entry->code, &old, sizeof(old)))
  69. jump_label_bug(entry, &old, &new);
  70. }
  71. s390_kernel_write((void *)entry->code, &new, sizeof(new));
  72. }
  73. static int __sm_arch_jump_label_transform(void *data)
  74. {
  75. struct insn_args *args = data;
  76. __jump_label_transform(args->entry, args->type, 0);
  77. return 0;
  78. }
  79. void arch_jump_label_transform(struct jump_entry *entry,
  80. enum jump_label_type type)
  81. {
  82. struct insn_args args;
  83. args.entry = entry;
  84. args.type = type;
  85. stop_machine(__sm_arch_jump_label_transform, &args, NULL);
  86. }
  87. void arch_jump_label_transform_static(struct jump_entry *entry,
  88. enum jump_label_type type)
  89. {
  90. __jump_label_transform(entry, type, 1);
  91. }
  92. #endif