selfmod.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  3. * Copyright (C) 2009 PetaLogix
  4. *
  5. * This file is subject to the terms and conditions of the GNU General Public
  6. * License. See the file "COPYING" in the main directory of this archive
  7. * for more details.
  8. */
  9. #include <linux/interrupt.h>
  10. #include <asm/selfmod.h>
  11. #undef DEBUG
  12. #if __GNUC__ > 3
  13. #error GCC 4 unsupported SELFMOD. Please disable SELFMOD from menuconfig.
  14. #endif
  15. #define OPCODE_IMM 0xB0000000
  16. #define OPCODE_LWI 0xE8000000
  17. #define OPCODE_LWI_MASK 0xEC000000
  18. #define OPCODE_RTSD 0xB60F0008 /* return from func: rtsd r15, 8 */
  19. #define OPCODE_ADDIK 0x30000000
  20. #define OPCODE_ADDIK_MASK 0xFC000000
  21. #define IMM_BASE (OPCODE_IMM | (BARRIER_BASE_ADDR >> 16))
  22. #define LWI_BASE (OPCODE_LWI | (BARRIER_BASE_ADDR & 0x0000ff00))
  23. #define LWI_BASE_MASK (OPCODE_LWI_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
  24. #define ADDIK_BASE (OPCODE_ADDIK | (BARRIER_BASE_ADDR & 0x0000ff00))
  25. #define ADDIK_BASE_MASK (OPCODE_ADDIK_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
  26. #define MODIFY_INSTR { \
  27. pr_debug("%s: curr instr, (%d):0x%x, next(%d):0x%x\n", \
  28. __func__, i, addr[i], i + 1, addr[i + 1]); \
  29. addr[i] = OPCODE_IMM + (base >> 16); \
  30. /* keep instruction opcode and add only last 16bits */ \
  31. addr[i + 1] = (addr[i + 1] & 0xffff00ff) + (base & 0xffff); \
  32. __invalidate_icache(addr[i]); \
  33. __invalidate_icache(addr[i + 1]); \
  34. pr_debug("%s: hack instr, (%d):0x%x, next(%d):0x%x\n", \
  35. __func__, i, addr[i], i + 1, addr[i + 1]); }
  36. /* NOTE
  37. * self-modified part of code for improvement of interrupt controller
  38. * save instruction in interrupt rutine
  39. */
  40. void selfmod_function(const int *arr_fce, const unsigned int base)
  41. {
  42. unsigned int flags, i, j, *addr = NULL;
  43. local_irq_save(flags);
  44. __disable_icache();
  45. /* zero terminated array */
  46. for (j = 0; arr_fce[j] != 0; j++) {
  47. /* get start address of function */
  48. addr = (unsigned int *) arr_fce[j];
  49. pr_debug("%s: func(%d) at 0x%x\n",
  50. __func__, j, (unsigned int) addr);
  51. for (i = 0; ; i++) {
  52. pr_debug("%s: instruction code at %d: 0x%x\n",
  53. __func__, i, addr[i]);
  54. if (addr[i] == IMM_BASE) {
  55. /* detecting of lwi (0xE8) or swi (0xF8) instr
  56. * I can detect both opcode with one mask */
  57. if ((addr[i + 1] & LWI_BASE_MASK) == LWI_BASE) {
  58. MODIFY_INSTR;
  59. } else /* detection addik for ack */
  60. if ((addr[i + 1] & ADDIK_BASE_MASK) ==
  61. ADDIK_BASE) {
  62. MODIFY_INSTR;
  63. }
  64. } else if (addr[i] == OPCODE_RTSD) {
  65. /* return from function means end of function */
  66. pr_debug("%s: end of array %d\n", __func__, i);
  67. break;
  68. }
  69. }
  70. }
  71. local_irq_restore(flags);
  72. } /* end of self-modified code */