sbi_trap.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  5. *
  6. * Authors:
  7. * Anup Patel <anup.patel@wdc.com>
  8. */
  9. #include <sbi/riscv_asm.h>
  10. #include <sbi/riscv_encoding.h>
  11. #include <sbi/sbi_console.h>
  12. #include <sbi/sbi_ecall.h>
  13. #include <sbi/sbi_error.h>
  14. #include <sbi/sbi_hart.h>
  15. #include <sbi/sbi_illegal_insn.h>
  16. #include <sbi/sbi_ipi.h>
  17. #include <sbi/sbi_misaligned_ldst.h>
  18. #include <sbi/sbi_timer.h>
  19. #include <sbi/sbi_trap.h>
  20. static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
  21. ulong mcause, ulong mtval,
  22. struct sbi_trap_regs *regs)
  23. {
  24. sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
  25. sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
  26. __func__, hartid, mcause, mtval);
  27. sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
  28. __func__, hartid, regs->mepc, regs->mstatus);
  29. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  30. hartid, "ra", regs->ra, "sp", regs->sp);
  31. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  32. hartid, "gp", regs->gp, "tp", regs->tp);
  33. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  34. hartid, "s0", regs->s0, "s1", regs->s1);
  35. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  36. hartid, "a0", regs->a0, "a1", regs->a1);
  37. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  38. hartid, "a2", regs->a2, "a3", regs->a3);
  39. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  40. hartid, "a4", regs->a4, "a5", regs->a5);
  41. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  42. hartid, "a6", regs->a6, "a7", regs->a7);
  43. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  44. hartid, "s2", regs->s2, "s3", regs->s3);
  45. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  46. hartid, "s4", regs->s4, "s5", regs->s5);
  47. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  48. hartid, "s6", regs->s6, "s7", regs->s7);
  49. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  50. hartid, "s8", regs->s8, "s9", regs->s9);
  51. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  52. hartid, "s10", regs->s10, "s11", regs->s11);
  53. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  54. hartid, "t0", regs->t0, "t1", regs->t1);
  55. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  56. hartid, "t2", regs->t2, "t3", regs->t3);
  57. sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
  58. hartid, "t4", regs->t4, "t5", regs->t5);
  59. sbi_printf("%s: hart%d: %s=0x%" PRILX "\n", __func__, hartid, "t6",
  60. regs->t6);
  61. sbi_hart_hang();
  62. }
  63. /**
  64. * Redirect trap to lower privledge mode (S-mode or U-mode)
  65. *
  66. * @param regs pointer to register state
  67. * @param scratch pointer to sbi_scratch of current HART
  68. * @param epc error PC for lower privledge mode
  69. * @param cause exception cause for lower privledge mode
  70. * @param tval trap value for lower privledge mode
  71. *
  72. * @return 0 on success and negative error code on failure
  73. */
  74. int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
  75. ulong epc, ulong cause, ulong tval)
  76. {
  77. ulong new_mstatus, prev_mode;
  78. /* Sanity check on previous mode */
  79. prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
  80. if (prev_mode != PRV_S && prev_mode != PRV_U)
  81. return SBI_ENOTSUPP;
  82. /* Update S-mode exception info */
  83. csr_write(CSR_STVAL, tval);
  84. csr_write(CSR_SEPC, epc);
  85. csr_write(CSR_SCAUSE, cause);
  86. /* Set MEPC to S-mode exception vector base */
  87. regs->mepc = csr_read(CSR_STVEC);
  88. /* Initial value of new MSTATUS */
  89. new_mstatus = regs->mstatus;
  90. /* Clear MPP, SPP, SPIE, and SIE */
  91. new_mstatus &=
  92. ~(MSTATUS_MPP | MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
  93. /* Set SPP */
  94. if (prev_mode == PRV_S)
  95. new_mstatus |= (1UL << MSTATUS_SPP_SHIFT);
  96. /* Set SPIE */
  97. if (regs->mstatus & MSTATUS_SIE)
  98. new_mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
  99. /* Set MPP */
  100. new_mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
  101. /* Set new value in MSTATUS */
  102. regs->mstatus = new_mstatus;
  103. return 0;
  104. }
  105. /**
  106. * Handle trap/interrupt
  107. *
  108. * This function is called by firmware linked to OpenSBI
  109. * library for handling trap/interrupt. It expects the
  110. * following:
  111. * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
  112. * 2. The 'mcause' CSR is having exception/interrupt cause
  113. * 3. The 'mtval' CSR is having additional trap information
  114. * 4. Stack pointer (SP) is setup for current HART
  115. * 5. Interrupts are disabled in MSTATUS CSR
  116. *
  117. * @param regs pointer to register state
  118. * @param scratch pointer to sbi_scratch of current HART
  119. */
  120. void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
  121. {
  122. int rc = SBI_ENOTSUPP;
  123. const char *msg = "trap handler failed";
  124. u32 hartid = sbi_current_hartid();
  125. ulong mcause = csr_read(CSR_MCAUSE);
  126. ulong mtval = csr_read(CSR_MTVAL);
  127. if (mcause & (1UL << (__riscv_xlen - 1))) {
  128. mcause &= ~(1UL << (__riscv_xlen - 1));
  129. switch (mcause) {
  130. case IRQ_M_TIMER:
  131. sbi_timer_process(scratch);
  132. break;
  133. case IRQ_M_SOFT:
  134. sbi_ipi_process(scratch);
  135. break;
  136. default:
  137. msg = "unhandled external interrupt";
  138. goto trap_error;
  139. };
  140. return;
  141. }
  142. switch (mcause) {
  143. case CAUSE_ILLEGAL_INSTRUCTION:
  144. rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
  145. msg = "illegal instruction handler failed";
  146. break;
  147. case CAUSE_MISALIGNED_LOAD:
  148. rc = sbi_misaligned_load_handler(hartid, mcause, regs, scratch);
  149. msg = "misaligned load handler failed";
  150. break;
  151. case CAUSE_MISALIGNED_STORE:
  152. rc = sbi_misaligned_store_handler(hartid, mcause, regs,
  153. scratch);
  154. msg = "misaligned store handler failed";
  155. break;
  156. case CAUSE_SUPERVISOR_ECALL:
  157. case CAUSE_HYPERVISOR_ECALL:
  158. rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
  159. msg = "ecall handler failed";
  160. break;
  161. default:
  162. /* If the trap came from S or U mode, redirect it there */
  163. rc = sbi_trap_redirect(regs, scratch, regs->mepc, mcause, mtval);
  164. break;
  165. };
  166. trap_error:
  167. if (rc) {
  168. sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL),
  169. regs);
  170. }
  171. }