fiq_glue.S 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*
  2. * Copyright (C) 2008 Google, Inc.
  3. *
  4. * This software is licensed under the terms of the GNU General Public
  5. * License version 2, as published by the Free Software Foundation, and
  6. * may be copied, distributed, and modified under those terms.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. */
  14. #include <linux/linkage.h>
  15. #include <asm/assembler.h>
  16. .text
  17. .global fiq_glue_end
  18. /* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
  19. ENTRY(fiq_glue)
  20. /* store pc, cpsr from previous mode, reserve space for spsr */
  21. mrs r12, spsr
  22. sub lr, lr, #4
  23. subs r10, #1
  24. bne nested_fiq
  25. str r12, [sp, #-8]!
  26. str lr, [sp, #-4]!
  27. /* store r8-r14 from previous mode */
  28. sub sp, sp, #(7 * 4)
  29. stmia sp, {r8-r14}^
  30. nop
  31. /* store r0-r7 from previous mode */
  32. stmfd sp!, {r0-r7}
  33. /* setup func(data,regs) arguments */
  34. mov r0, r9
  35. mov r1, sp
  36. mov r3, r8
  37. mov r7, sp
  38. /* Get sp and lr from non-user modes */
  39. and r4, r12, #MODE_MASK
  40. cmp r4, #USR_MODE
  41. beq fiq_from_usr_mode
  42. mov r7, sp
  43. orr r4, r4, #(PSR_I_BIT | PSR_F_BIT)
  44. msr cpsr_c, r4
  45. str sp, [r7, #(4 * 13)]
  46. str lr, [r7, #(4 * 14)]
  47. mrs r5, spsr
  48. str r5, [r7, #(4 * 17)]
  49. cmp r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
  50. /* use fiq stack if we reenter this mode */
  51. subne sp, r7, #(4 * 3)
  52. fiq_from_usr_mode:
  53. msr cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
  54. mov r2, sp
  55. sub sp, r7, #12
  56. stmfd sp!, {r2, ip, lr}
  57. /* call func(data,regs) */
  58. blx r3
  59. ldmfd sp, {r2, ip, lr}
  60. mov sp, r2
  61. /* restore/discard saved state */
  62. cmp r4, #USR_MODE
  63. beq fiq_from_usr_mode_exit
  64. msr cpsr_c, r4
  65. ldr sp, [r7, #(4 * 13)]
  66. ldr lr, [r7, #(4 * 14)]
  67. msr spsr_cxsf, r5
  68. fiq_from_usr_mode_exit:
  69. msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
  70. ldmfd sp!, {r0-r7}
  71. ldr lr, [sp, #(4 * 7)]
  72. ldr r12, [sp, #(4 * 8)]
  73. add sp, sp, #(10 * 4)
  74. exit_fiq:
  75. msr spsr_cxsf, r12
  76. add r10, #1
  77. cmp r11, #0
  78. moveqs pc, lr
  79. bx r11 /* jump to custom fiq return function */
  80. nested_fiq:
  81. orr r12, r12, #(PSR_F_BIT)
  82. b exit_fiq
  83. fiq_glue_end:
  84. ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */
  85. stmfd sp!, {r4}
  86. mrs r4, cpsr
  87. msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
  88. movs r8, r0
  89. mov r9, r1
  90. mov sp, r2
  91. mov r11, r3
  92. moveq r10, #0
  93. movne r10, #1
  94. msr cpsr_c, r4
  95. ldmfd sp!, {r4}
  96. bx lr