main.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // See LICENSE for license details.
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <stdlib.h>
  5. #include "nuclei_sdk_soc.h"
  6. // 2048 is enough
  7. #define SMODE_STACK_SIZE 2048
  8. /* Create a stack for supervisor mode execution */
  9. uint8_t smode_stack[SMODE_STACK_SIZE] __attribute__((aligned(16)));
  10. uintptr_t smode_sp = (uintptr_t) (smode_stack + sizeof(smode_stack));
  11. static void mmode_exception_handler(unsigned long mcause, unsigned long sp)
  12. {
  13. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  14. printf("\r\nmmode_exception_handler enters\r\n");
  15. switch (mcause & MCAUSE_CAUSE) {
  16. case IlleIns_EXCn:
  17. printf("Illegal instruction fault occurs, mcause: 0x%lx, mepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  18. break;
  19. case SmodeEcall_EXCn:
  20. printf("Environment call from S-mode, mcause: 0x%lx, mepc: 0x%lx, disable the medeleg\r\n", exc_frame->cause, exc_frame->epc);
  21. __set_medeleg(0);
  22. break;
  23. default: break;
  24. }
  25. exc_frame->epc += 4; // The illegal instruction and ecall takes 4 bytes
  26. }
  27. static void smode_exception_handler(unsigned long scause, unsigned long sp)
  28. {
  29. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  30. printf("\r\nsmode_exception_handler enters\r\n");
  31. switch (scause & SCAUSE_CAUSE) {
  32. case IlleIns_EXCn:
  33. printf("Illegal instruction fault occurs, scause: 0x%lx, sepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  34. break;
  35. default: break;
  36. }
  37. exc_frame->epc += 4; // The illegal instruction and ecall takes 4 bytes
  38. }
  39. static void trigger_illegal_inst(void)
  40. {
  41. // The illegal instruction takes 4 bytes
  42. __ASM volatile(".word 0xffffffff");
  43. }
  44. static void trigger_ecall(void)
  45. {
  46. // The ecall instruction takes 4 bytes
  47. __ASM volatile("ecall");
  48. }
  49. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  50. // it's not reliable to use sp range to check privilege mode in exception/interrupt handler
  51. void print_sp_judge_privilege_mode(void)
  52. {
  53. uintptr_t sp;
  54. __asm__ volatile("add %0, x0, sp" :"=r"(sp));
  55. printf("Current sp is 0x%lx, ", (unsigned long)sp);
  56. if ( ((uint8_t *)sp <= &(smode_stack[SMODE_STACK_SIZE - 1])) && ((uint8_t *)sp >= &(smode_stack[0])) ) {
  57. printf("so it is in Supervisor Mode!\r\n");
  58. }
  59. else {
  60. printf("so it is in Machine Mode!\r\n");
  61. }
  62. }
  63. static void supervisor_mode_entry_point(void)
  64. {
  65. printf("[IN S-MODE ENTRY POINT] Hello Supervisor Mode!!!\r\n");
  66. print_sp_judge_privilege_mode();
  67. printf("\r\n1. The first time, smode's illegal instruction will be delegated to smode's handler");
  68. trigger_illegal_inst();
  69. printf("\r\n2. Ecall to mmode to disable the medeleg");
  70. trigger_ecall();
  71. printf("\r\n3. Then smode's illegal instruction will be handled in mmode");
  72. trigger_illegal_inst();
  73. printf("\r\nBack to S mode! S mode exception test finish and pass!\r\n");
  74. #ifdef CFG_SIMULATION
  75. // directly exit if in nuclei internally simulation
  76. SIMULATION_EXIT(0);
  77. #endif
  78. while(1);
  79. }
  80. #endif
  81. int main(void)
  82. {
  83. #if defined(__PMP_PRESENT) && (__PMP_PRESENT == 1) && defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  84. CSR_MCFGINFO_Type mcfg_info;
  85. CSR_MISA_Type misa;
  86. // Generally, Nuclei CPU's pmp/smpu granularity is 2^12 = 4KBytes(order should at least be 12), you should refer to the databook.
  87. // set pmp, S mode can access all address range
  88. pmp_config pmp_cfg = {
  89. /* M mode grants S and U mode with full permission of the whole address range */
  90. .protection = PMP_L | PMP_R | PMP_W | PMP_X,
  91. /* Memory region range 2^__RISCV_XLEN bytes */
  92. .order = __RISCV_XLEN,
  93. /* Initial base address is 0 */
  94. .base_addr = 0,
  95. };
  96. __set_PMPENTRYx(0, &pmp_cfg);
  97. mcfg_info.d = __RV_CSR_READ(CSR_MCFG_INFO);
  98. misa.d = __RV_CSR_READ(CSR_MISA);
  99. if (0 == misa.b.s) {
  100. printf("INFO: S-Mode is required, will not run this example!\r\n");
  101. return 0;
  102. }
  103. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT != 0)
  104. if (0 == mcfg_info.b.clic) {
  105. printf("You expect ECLIC present, but ECLIC is not present, will not run this example!\r\n");
  106. printf("You can rebuild and run this example with extra make option XLCFG_ECLIC=0 if ECLIC not present!\r\n");
  107. return 0;
  108. }
  109. #endif
  110. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  111. if (0 == misa.b.s) {
  112. printf("You expect SMODE present, but SMODE is not present, will not run this example!\r\n");
  113. printf("You can rebuild and run this example with extra make option XLCFG_SMODE=0 if SMODE not present!\r\n");
  114. return 0;
  115. }
  116. #endif
  117. /* register corresponding exception */
  118. Exception_Register_EXC(IlleIns_EXCn, (unsigned long)mmode_exception_handler);
  119. Exception_Register_EXC(SmodeEcall_EXCn, (unsigned long)mmode_exception_handler);
  120. /* Corresponding exceptions occurs in S/U-mode will be delegated to S-mode */
  121. __set_medeleg(ILLEGAL_INSTRUCTION);
  122. Exception_Register_EXC_S(IlleIns_EXCn, (unsigned long)smode_exception_handler);
  123. printf("Drop to S-Mode now\n\r");
  124. /* Drop to S mode */
  125. __switch_mode(PRV_S, smode_sp, supervisor_mode_entry_point);
  126. #else
  127. printf("[ERROR]__SMODE_PRESENT & __PMP_PRESENT must be defined as 1 in <Device>.h!\r\n");
  128. #endif
  129. return 0;
  130. }