sbi_hart.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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_barrier.h>
  11. #include <sbi/riscv_encoding.h>
  12. #include <sbi/riscv_fp.h>
  13. #include <sbi/sbi_bitops.h>
  14. #include <sbi/sbi_console.h>
  15. #include <sbi/sbi_error.h>
  16. #include <sbi/sbi_hart.h>
  17. #include <sbi/sbi_math.h>
  18. #include <sbi/sbi_platform.h>
  19. extern void __sbi_expected_trap(void);
  20. extern void __sbi_expected_trap_hext(void);
  21. void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
  22. static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
  23. {
  24. const struct sbi_platform *plat = sbi_platform_ptr(scratch);
  25. unsigned long mstatus_val = 0;
  26. /* Enable FPU */
  27. if (misa_extension('D') || misa_extension('F'))
  28. mstatus_val |= MSTATUS_FS;
  29. /* Enable Vector context */
  30. if (misa_extension('V'))
  31. mstatus_val |= MSTATUS_VS;
  32. csr_write(CSR_MSTATUS, mstatus_val);
  33. /* Enable user/supervisor use of perf counters */
  34. if (misa_extension('S') && sbi_platform_has_scounteren(plat))
  35. csr_write(CSR_SCOUNTEREN, -1);
  36. if (sbi_platform_has_mcounteren(plat))
  37. csr_write(CSR_MCOUNTEREN, -1);
  38. /* Disable all interrupts */
  39. csr_write(CSR_MIE, 0);
  40. /* Disable S-mode paging */
  41. if (misa_extension('S'))
  42. csr_write(CSR_SATP, 0);
  43. }
  44. static int fp_init(u32 hartid)
  45. {
  46. #ifdef __riscv_flen
  47. int i;
  48. #endif
  49. if (!misa_extension('D') && !misa_extension('F'))
  50. return 0;
  51. if (!(csr_read(CSR_MSTATUS) & MSTATUS_FS))
  52. return SBI_EINVAL;
  53. #ifdef __riscv_flen
  54. for (i = 0; i < 32; i++)
  55. init_fp_reg(i);
  56. csr_write(CSR_FCSR, 0);
  57. #endif
  58. return 0;
  59. }
  60. static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
  61. {
  62. const struct sbi_platform *plat = sbi_platform_ptr(scratch);
  63. unsigned long interrupts, exceptions;
  64. if (!misa_extension('S'))
  65. /* No delegation possible as mideleg does not exist */
  66. return 0;
  67. /* Send M-mode interrupts and most exceptions to S-mode */
  68. interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
  69. exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
  70. (1U << CAUSE_USER_ECALL);
  71. if (sbi_platform_has_mfaults_delegation(plat))
  72. exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) |
  73. (1U << CAUSE_LOAD_PAGE_FAULT) |
  74. (1U << CAUSE_STORE_PAGE_FAULT);
  75. /*
  76. * If hypervisor extension available then we only handle hypervisor
  77. * calls (i.e. ecalls from HS-mode) in M-mode.
  78. *
  79. * The HS-mode will additionally handle supervisor calls (i.e. ecalls
  80. * from VS-mode), Guest page faults and Virtual interrupts.
  81. */
  82. if (misa_extension('H')) {
  83. exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
  84. exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
  85. exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
  86. exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
  87. }
  88. csr_write(CSR_MIDELEG, interrupts);
  89. csr_write(CSR_MEDELEG, exceptions);
  90. return 0;
  91. }
  92. void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
  93. {
  94. #if __riscv_xlen == 32
  95. sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
  96. sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
  97. #else
  98. sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
  99. sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
  100. #endif
  101. }
  102. void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
  103. {
  104. const struct sbi_platform *plat = sbi_platform_ptr(scratch);
  105. unsigned long prot, addr, size;
  106. unsigned int i;
  107. if (!sbi_platform_has_pmp(plat))
  108. return;
  109. for (i = 0; i < PMP_COUNT; i++) {
  110. pmp_get(i, &prot, &addr, &size);
  111. if (!(prot & PMP_A))
  112. continue;
  113. #if __riscv_xlen == 32
  114. sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
  115. #else
  116. sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
  117. #endif
  118. i, addr, addr + size - 1);
  119. if (prot & PMP_L)
  120. sbi_printf(",L");
  121. if (prot & PMP_R)
  122. sbi_printf(",R");
  123. if (prot & PMP_W)
  124. sbi_printf(",W");
  125. if (prot & PMP_X)
  126. sbi_printf(",X");
  127. sbi_printf(")\n");
  128. }
  129. }
  130. int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
  131. unsigned long attr)
  132. {
  133. unsigned long prot, size, i, tempaddr;
  134. const struct sbi_platform *plat = sbi_platform_ptr(scratch);
  135. if (!sbi_platform_has_pmp(plat))
  136. return SBI_OK;
  137. for (i = 0; i < PMP_COUNT; i++) {
  138. pmp_get(i, &prot, &tempaddr, &size);
  139. if (!(prot & PMP_A))
  140. continue;
  141. if (tempaddr <= addr && addr <= tempaddr + size)
  142. if (!(prot & attr))
  143. return SBI_INVALID_ADDR;
  144. }
  145. return SBI_OK;
  146. }
  147. static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
  148. {
  149. u32 i, pmp_idx = 0, count;
  150. unsigned long fw_start, fw_size_log2;
  151. ulong prot, addr, log2size;
  152. const struct sbi_platform *plat = sbi_platform_ptr(scratch);
  153. if (!sbi_platform_has_pmp(plat))
  154. return 0;
  155. /* Firmware PMP region to protect OpenSBI firmware */
  156. fw_size_log2 = log2roundup(scratch->fw_size);
  157. fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
  158. pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
  159. /* Platform specific PMP regions */
  160. count = sbi_platform_pmp_region_count(plat, hartid);
  161. for (i = 0; i < count && pmp_idx < (PMP_COUNT - 1); i++) {
  162. if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
  163. &log2size))
  164. continue;
  165. pmp_set(pmp_idx++, prot, addr, log2size);
  166. }
  167. /*
  168. * Default PMP region for allowing S-mode and U-mode access to
  169. * memory not covered by:
  170. * 1) Firmware PMP region
  171. * 2) Platform specific PMP regions
  172. */
  173. pmp_set(pmp_idx++, PMP_R | PMP_W | PMP_X, 0, __riscv_xlen);
  174. return 0;
  175. }
  176. int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
  177. {
  178. int rc;
  179. if (cold_boot) {
  180. if (misa_extension('H'))
  181. sbi_hart_expected_trap = &__sbi_expected_trap_hext;
  182. }
  183. mstatus_init(scratch, hartid);
  184. rc = fp_init(hartid);
  185. if (rc)
  186. return rc;
  187. rc = delegate_traps(scratch, hartid);
  188. if (rc)
  189. return rc;
  190. return pmp_init(scratch, hartid);
  191. }
  192. void __attribute__((noreturn)) sbi_hart_hang(void)
  193. {
  194. while (1)
  195. wfi();
  196. __builtin_unreachable();
  197. }
  198. void __attribute__((noreturn))
  199. sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
  200. unsigned long next_addr, unsigned long next_mode,
  201. bool next_virt)
  202. {
  203. #if __riscv_xlen == 32
  204. unsigned long val, valH;
  205. #else
  206. unsigned long val;
  207. #endif
  208. switch (next_mode) {
  209. case PRV_M:
  210. break;
  211. case PRV_S:
  212. if (!misa_extension('S'))
  213. sbi_hart_hang();
  214. break;
  215. case PRV_U:
  216. if (!misa_extension('U'))
  217. sbi_hart_hang();
  218. break;
  219. default:
  220. sbi_hart_hang();
  221. }
  222. val = csr_read(CSR_MSTATUS);
  223. val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
  224. val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
  225. #if __riscv_xlen == 32
  226. if (misa_extension('H')) {
  227. valH = csr_read(CSR_MSTATUSH);
  228. if (next_virt)
  229. valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
  230. else
  231. valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
  232. csr_write(CSR_MSTATUSH, valH);
  233. }
  234. #else
  235. if (misa_extension('H')) {
  236. if (next_virt)
  237. val = INSERT_FIELD(val, MSTATUS_MPV, 1);
  238. else
  239. val = INSERT_FIELD(val, MSTATUS_MPV, 0);
  240. }
  241. #endif
  242. csr_write(CSR_MSTATUS, val);
  243. csr_write(CSR_MEPC, next_addr);
  244. if (next_mode == PRV_S) {
  245. csr_write(CSR_STVEC, next_addr);
  246. csr_write(CSR_SSCRATCH, 0);
  247. csr_write(CSR_SIE, 0);
  248. csr_write(CSR_SATP, 0);
  249. } else if (next_mode == PRV_U) {
  250. csr_write(CSR_UTVEC, next_addr);
  251. csr_write(CSR_USCRATCH, 0);
  252. csr_write(CSR_UIE, 0);
  253. }
  254. register unsigned long a0 asm("a0") = arg0;
  255. register unsigned long a1 asm("a1") = arg1;
  256. __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
  257. __builtin_unreachable();
  258. }