sbi_emulate_csr.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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_bitops.h>
  12. #include <sbi/sbi_console.h>
  13. #include <sbi/sbi_emulate_csr.h>
  14. #include <sbi/sbi_error.h>
  15. #include <sbi/sbi_hart.h>
  16. #include <sbi/sbi_scratch.h>
  17. #include <sbi/sbi_timer.h>
  18. #include <sbi/sbi_trap.h>
  19. static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
  20. {
  21. ulong cen = -1UL;
  22. struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
  23. if (prev_mode <= PRV_S) {
  24. if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
  25. cen &= csr_read(CSR_MCOUNTEREN);
  26. if (virt)
  27. cen &= csr_read(CSR_HCOUNTEREN);
  28. } else {
  29. cen = 0;
  30. }
  31. }
  32. if (prev_mode == PRV_U) {
  33. if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
  34. cen &= csr_read(CSR_SCOUNTEREN);
  35. else
  36. cen = 0;
  37. }
  38. return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
  39. }
  40. int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
  41. ulong *csr_val)
  42. {
  43. int ret = 0;
  44. struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
  45. ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
  46. #if __riscv_xlen == 32
  47. bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
  48. #else
  49. bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
  50. #endif
  51. switch (csr_num) {
  52. case CSR_HTIMEDELTA:
  53. if (prev_mode == PRV_S && !virt)
  54. *csr_val = sbi_timer_get_delta();
  55. else
  56. ret = SBI_ENOTSUPP;
  57. break;
  58. case CSR_CYCLE:
  59. if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
  60. return SBI_ENOTSUPP;
  61. *csr_val = csr_read(CSR_MCYCLE);
  62. break;
  63. case CSR_TIME:
  64. /*
  65. * We emulate TIME CSR for both Host (HS/U-mode) and
  66. * Guest (VS/VU-mode).
  67. *
  68. * Faster TIME CSR reads are critical for good performance
  69. * in S-mode software so we don't check CSR permissions.
  70. */
  71. *csr_val = (virt) ? sbi_timer_virt_value():
  72. sbi_timer_value();
  73. break;
  74. case CSR_INSTRET:
  75. if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
  76. return SBI_ENOTSUPP;
  77. *csr_val = csr_read(CSR_MINSTRET);
  78. break;
  79. #if __riscv_xlen == 32
  80. case CSR_HTIMEDELTAH:
  81. if (prev_mode == PRV_S && !virt)
  82. *csr_val = sbi_timer_get_delta() >> 32;
  83. else
  84. ret = SBI_ENOTSUPP;
  85. break;
  86. case CSR_CYCLEH:
  87. if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
  88. return SBI_ENOTSUPP;
  89. *csr_val = csr_read(CSR_MCYCLEH);
  90. break;
  91. case CSR_TIMEH:
  92. /* Refer comments on TIME CSR above. */
  93. *csr_val = (virt) ? sbi_timer_virt_value() >> 32:
  94. sbi_timer_value() >> 32;
  95. break;
  96. case CSR_INSTRETH:
  97. if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
  98. return SBI_ENOTSUPP;
  99. *csr_val = csr_read(CSR_MINSTRETH);
  100. break;
  101. #endif
  102. #define switchcase_hpm(__uref, __mref, __csr) \
  103. case __csr: \
  104. if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
  105. return SBI_ENOTSUPP; \
  106. if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
  107. return SBI_ENOTSUPP; \
  108. *csr_val = csr_read(__mref + __csr - __uref); \
  109. break;
  110. #define switchcase_hpm_2(__uref, __mref, __csr) \
  111. switchcase_hpm(__uref, __mref, __csr + 0) \
  112. switchcase_hpm(__uref, __mref, __csr + 1)
  113. #define switchcase_hpm_4(__uref, __mref, __csr) \
  114. switchcase_hpm_2(__uref, __mref, __csr + 0) \
  115. switchcase_hpm_2(__uref, __mref, __csr + 2)
  116. #define switchcase_hpm_8(__uref, __mref, __csr) \
  117. switchcase_hpm_4(__uref, __mref, __csr + 0) \
  118. switchcase_hpm_4(__uref, __mref, __csr + 4)
  119. #define switchcase_hpm_16(__uref, __mref, __csr) \
  120. switchcase_hpm_8(__uref, __mref, __csr + 0) \
  121. switchcase_hpm_8(__uref, __mref, __csr + 8)
  122. switchcase_hpm(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER3)
  123. switchcase_hpm_4(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER4)
  124. switchcase_hpm_8(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER8)
  125. switchcase_hpm_16(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER16)
  126. #if __riscv_xlen == 32
  127. switchcase_hpm(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER3H)
  128. switchcase_hpm_4(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER4H)
  129. switchcase_hpm_8(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER8H)
  130. switchcase_hpm_16(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER16H)
  131. #endif
  132. #undef switchcase_hpm_16
  133. #undef switchcase_hpm_8
  134. #undef switchcase_hpm_4
  135. #undef switchcase_hpm_2
  136. #undef switchcase_hpm
  137. default:
  138. ret = SBI_ENOTSUPP;
  139. break;
  140. };
  141. if (ret)
  142. sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
  143. __func__, current_hartid(), csr_num);
  144. return ret;
  145. }
  146. int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
  147. ulong csr_val)
  148. {
  149. int ret = 0;
  150. ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
  151. #if __riscv_xlen == 32
  152. bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
  153. #else
  154. bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
  155. #endif
  156. switch (csr_num) {
  157. case CSR_HTIMEDELTA:
  158. if (prev_mode == PRV_S && !virt)
  159. sbi_timer_set_delta(csr_val);
  160. else
  161. ret = SBI_ENOTSUPP;
  162. break;
  163. #if __riscv_xlen == 32
  164. case CSR_HTIMEDELTAH:
  165. if (prev_mode == PRV_S && !virt)
  166. sbi_timer_set_delta_upper(csr_val);
  167. else
  168. ret = SBI_ENOTSUPP;
  169. break;
  170. #endif
  171. default:
  172. ret = SBI_ENOTSUPP;
  173. break;
  174. };
  175. if (ret)
  176. sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
  177. __func__, current_hartid(), csr_num);
  178. return ret;
  179. }