main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #define UMODE_STACK_SIZE SMODE_STACK_SIZE
  9. // Shared code region: Execute only on both S and U mode
  10. #define S_U_EXECUTE_ONLY SMPU_S | SMPU_W
  11. // Shared code region: Execute only on U mode, read/execute on S mode
  12. #define S_U_EXECUTE_S_READ SMPU_S | SMPU_W | SMPU_X
  13. // Shared data region: Read/write for both S and U mode
  14. #define S_U_READ_WRITE SMPU_W | SMPU_X
  15. extern char ILM_MEMORY_BASE[], ILM_MEMORY_SIZE[], DLM_MEMORY_BASE[], DLM_MEMORY_SIZE[], DDR_MEMORY_BASE[], DDR_MEMORY_SIZE[], DDR_MEMORY_ROM_SIZE[], FLASH_MEMORY_BASE[],
  16. FLASH_MEMORY_SIZE[], SRAM_MEMORY_BASE[], SRAM_MEMORY_SIZE[], SRAM_MEMORY_ROM_SIZE[];
  17. /* Create a stack for supervisor mode execution */
  18. uint8_t smode_stack[SMODE_STACK_SIZE] __attribute__((aligned(16)));
  19. uintptr_t smode_sp = (uintptr_t) (smode_stack + sizeof(smode_stack));
  20. /* Create a stack for user mode execution */
  21. uint8_t umode_stack[UMODE_STACK_SIZE] __attribute__((aligned(16)));
  22. uintptr_t umode_sp = (uintptr_t) (umode_stack + sizeof(umode_stack));
  23. static void smode_exception_handler(unsigned long scause, unsigned long sp)
  24. {
  25. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  26. printf("\r\nsmode_exception_handler enters\r\n");
  27. switch (scause & SCAUSE_CAUSE) {
  28. case IlleIns_EXCn:
  29. printf("Illegal instruction fault occurs, scause: 0x%lx, sepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  30. break;
  31. case UmodeEcall_EXCn:
  32. printf("Environment call from U-mode, scause: 0x%lx, sepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  33. break;
  34. default: break;
  35. }
  36. exc_frame->epc += 4; // The illegal instruction and ecall takes 4 bytes
  37. }
  38. static void mmode_exception_handler(unsigned long mcause, unsigned long sp)
  39. {
  40. EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
  41. printf("\r\nmmode_exception_handler enters\r\n");
  42. switch (mcause & MCAUSE_CAUSE) {
  43. case IlleIns_EXCn:
  44. printf("Illegal instruction fault occurs, mcause: 0x%lx, mepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  45. break;
  46. case UmodeEcall_EXCn:
  47. printf("Environment call from U-mode, mcause: 0x%lx, mepc: 0x%lx\r\n", exc_frame->cause, exc_frame->epc);
  48. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  49. /* Corresponding exceptions occurs in S/U-mode will be delegated to S-mode if delegating enabled */
  50. __set_medeleg(ILLEGAL_INSTRUCTION | USER_ECALL);
  51. #endif
  52. break;
  53. default: break;
  54. }
  55. exc_frame->epc += 4; // The illegal instruction and ecall takes 4 bytes
  56. }
  57. static void trigger_illegal_inst(void)
  58. {
  59. // The illegal instruction takes 4 bytes
  60. __ASM volatile(".word 0xffffffff");
  61. }
  62. static void trigger_ecall(void)
  63. {
  64. // The ecall takes 4 bytes
  65. __ASM volatile("ecall");
  66. }
  67. void print_sp_judge_privilege_mode(void)
  68. {
  69. uintptr_t sp;
  70. __asm__ volatile("add %0, x0, sp" :"=r"(sp));
  71. printf("Current sp is 0x%lx, ", (unsigned long)sp);
  72. if ( ((uint8_t *)sp <= &(smode_stack[SMODE_STACK_SIZE - 1])) && ((uint8_t *)sp >= &(smode_stack[0])) ) {
  73. printf("so it is in Supervisor Mode!\r\n");
  74. }
  75. else if ( ((uint8_t *)sp <= &(umode_stack[UMODE_STACK_SIZE - 1])) && ((uint8_t *)sp >= &(umode_stack[0])) ) {
  76. printf("so it is in User Mode!\r\n");
  77. }
  78. else {
  79. printf("so it is in Machine Mode!\r\n");
  80. }
  81. }
  82. static void user_mode_entry_point(void)
  83. {
  84. CSR_MSTATUS_Type mstatus;
  85. mstatus.d = __RV_CSR_READ(CSR_MSTATUS);
  86. if (PRV_S == mstatus.b.mpp) {
  87. printf("\r\nFrom S mode switch into U mode\r\n");
  88. } else if (PRV_M == mstatus.b.mpp) {
  89. printf("\r\nFrom M mode switch into U mode\r\n");
  90. }
  91. print_sp_judge_privilege_mode();
  92. printf("\r\n1. The first time, umode's illegal instruction and ecall will be handled in mmode");
  93. trigger_illegal_inst();
  94. printf("\r\n2. Ecall to mmode");
  95. trigger_ecall();
  96. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  97. printf("\r\n3. Then umode's illegal instruction and ecall will be delegated to smode's handler");
  98. trigger_illegal_inst();
  99. trigger_ecall();
  100. #endif
  101. printf("\r\nBack to U mode! U mode exception test finish and pass!\r\n");
  102. #ifdef CFG_SIMULATION
  103. // directly exit if in nuclei internally simulation
  104. SIMULATION_EXIT(0);
  105. #endif
  106. while (1);
  107. }
  108. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  109. // it's not reliable to use sp range to check privilege mode in exception/interrupt handler
  110. static void supervisor_mode_entry_point(void)
  111. {
  112. printf("[IN S-MODE ENTRY POINT] Hello Supervisor Mode!!!\r\n");
  113. print_sp_judge_privilege_mode();
  114. /* Drop to U mode from S mode */
  115. __s_switch_mode(PRV_U, umode_sp, user_mode_entry_point);
  116. #ifdef CFG_SIMULATION
  117. // directly exit if in nuclei internally simulation
  118. SIMULATION_EXIT(0);
  119. #endif
  120. while (1);
  121. }
  122. #endif
  123. int main(void)
  124. {
  125. #if defined(__PMP_PRESENT) && (__PMP_PRESENT == 1)
  126. CSR_MCFGINFO_Type mcfg_info;
  127. CSR_MISA_Type misa;
  128. mcfg_info.d = __RV_CSR_READ(CSR_MCFG_INFO);
  129. misa.d = __RV_CSR_READ(CSR_MISA);
  130. #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT != 0)
  131. if (0 == mcfg_info.b.clic) {
  132. printf("You expect ECLIC present, but ECLIC is not present, will not run this example!\r\n");
  133. printf("You can rebuild and run this example with extra make option XLCFG_ECLIC=0 if ECLIC not present!\r\n");
  134. return 0;
  135. }
  136. #endif
  137. #if defined(__SMPU_PRESENT) && (__SMPU_PRESENT == 1)
  138. #if defined(CPU_SERIES) && CPU_SERIES == 100
  139. #else
  140. smpu_config smpu_config_rw1, smpu_config_x1, smpu_config_x2, smpu_config_rw2;
  141. if (1 == mcfg_info.b.tee) {
  142. printf("Configure SMPU due to TEE Present, and it depends on Nuclei evalsoc's linker memory map!\r\n");
  143. // For simplicity to show U mode's exception and delegation to S mode,
  144. // this demo grant S and U the same permissions with memory range as big as possible, and can't be used as a practical reference
  145. /* Configuration of S and U shared r/w region:0x0 ~ 0x1FFF FFFF, containing peripheral device range like uart*/
  146. smpu_config_rw1.protection = S_U_READ_WRITE | SMPU_A_NAPOT;
  147. smpu_config_rw1.order = 29;
  148. smpu_config_rw1.base_addr = 0;
  149. if (DOWNLOAD_MODE == DOWNLOAD_MODE_FLASH || DOWNLOAD_MODE == DOWNLOAD_MODE_ILM) {
  150. /* Configuration of S and U shared code region: 0x2000 0000 ~ 0x207F FFFF, containing flash */
  151. smpu_config_x1.protection = S_U_EXECUTE_S_READ | SMPU_A_NAPOT;
  152. smpu_config_x1.order = __CTZ((unsigned long)FLASH_MEMORY_SIZE);
  153. smpu_config_x1.base_addr = (unsigned long)FLASH_MEMORY_BASE;
  154. /* Configuration of S and U shared code region: 0x8000 0000 ~ 0x8FFF FFFF, containing ilm */
  155. smpu_config_x2.protection = S_U_EXECUTE_ONLY | SMPU_A_NAPOT;
  156. smpu_config_x2.order = __CTZ((unsigned long)ILM_MEMORY_SIZE);
  157. smpu_config_x2.base_addr = (unsigned long)ILM_MEMORY_BASE;
  158. /* Configuration of S and U shared r/w region:0x9000 0000 ~ 0x9FFF FFFF, containing dlm */
  159. smpu_config_rw2.protection = S_U_READ_WRITE | SMPU_A_NAPOT;
  160. smpu_config_rw2.order = __CTZ((unsigned long)DLM_MEMORY_SIZE);
  161. smpu_config_rw2.base_addr = (unsigned long)DLM_MEMORY_BASE;
  162. } else if (DOWNLOAD_MODE == DOWNLOAD_MODE_SRAM) {
  163. /* Configuration of S and U shared code region: 0xA000 0000 ~ 0x7FF FFFF, containing sram */
  164. smpu_config_x2.protection = S_U_EXECUTE_ONLY | SMPU_A_NAPOT;
  165. smpu_config_x2.order = __CTZ((unsigned long)SRAM_MEMORY_ROM_SIZE);
  166. smpu_config_x2.base_addr = (unsigned long)SRAM_MEMORY_BASE;
  167. /* Configuration of S and U shared data region: 0xA800 0000 ~ 0xAFFF FFFF, containing ddr */
  168. smpu_config_rw2.protection = S_U_READ_WRITE | SMPU_A_NAPOT;
  169. smpu_config_rw2.order = __CTZ((unsigned long)SRAM_MEMORY_SIZE - (unsigned long)SRAM_MEMORY_ROM_SIZE);
  170. smpu_config_rw2.base_addr = (unsigned long)SRAM_MEMORY_BASE + (unsigned long)SRAM_MEMORY_ROM_SIZE;
  171. } else if (DOWNLOAD_MODE == DOWNLOAD_MODE_DDR) {
  172. /* Configuration of S and U shared code region: 0xA000 0000 ~ 0x7FF FFFF, containing ddr */
  173. smpu_config_x2.protection = S_U_EXECUTE_ONLY | SMPU_A_NAPOT;
  174. smpu_config_x2.order = __CTZ((unsigned long)DDR_MEMORY_ROM_SIZE);
  175. smpu_config_x2.base_addr = (unsigned long)DDR_MEMORY_BASE;
  176. /* Configuration of S and U shared data region: 0xA800 0000 ~ 0xAFFF FFFF, containing ddr */
  177. smpu_config_rw2.protection = S_U_READ_WRITE | SMPU_A_NAPOT;
  178. smpu_config_rw2.order = __CTZ((unsigned long)DDR_MEMORY_SIZE - (unsigned long)DDR_MEMORY_ROM_SIZE);
  179. smpu_config_rw2.base_addr = (unsigned long)DDR_MEMORY_BASE + (unsigned long)DDR_MEMORY_ROM_SIZE;
  180. } else {
  181. printf("Unsupported flashxip download mode, will not run this example!\r\n");
  182. return 0;
  183. }
  184. // enable smpu entries
  185. __set_SMPUENTRYx(0, &smpu_config_rw1);
  186. __set_SMPUENTRYx(1, &smpu_config_x1);
  187. __set_SMPUENTRYx(2, &smpu_config_x2);
  188. __set_SMPUENTRYx(3, &smpu_config_rw2);
  189. __set_SMPUSWITCHx(0xF);
  190. } else {
  191. printf("You expect SMPU present, but SMPU is not present, will not run this example!\r\n");
  192. printf("You can rebuild and run this example with extra make option XLCFG_SMPU=0 if SMPU not present!\r\n");
  193. return 0;
  194. }
  195. #endif
  196. #else
  197. if (1 == mcfg_info.b.tee) {
  198. printf("You expect SMPU not present, but SMPU is present, will not run this example!\r\n");
  199. printf("You can rebuild and run this example with extra make option XLCFG_SMPU=1 if SMPU is present!\r\n");
  200. return 0;
  201. }
  202. #endif
  203. // set pmp, S mode can access all address range
  204. pmp_config pmp_cfg = {
  205. /* M mode grants S and U mode with full permission of the whole address range */
  206. .protection = PMP_L | PMP_R | PMP_W | PMP_X,
  207. /* Memory region range 2^__RISCV_XLEN bytes */
  208. .order = __RISCV_XLEN,
  209. /* Initial base address is 0 */
  210. .base_addr = 0,
  211. };
  212. __set_PMPENTRYx(0, &pmp_cfg);
  213. Exception_Register_EXC(IlleIns_EXCn, (unsigned long)mmode_exception_handler);
  214. Exception_Register_EXC(UmodeEcall_EXCn, (unsigned long)mmode_exception_handler);
  215. #if defined(__SMODE_PRESENT) && (__SMODE_PRESENT == 1)
  216. if (0 == misa.b.s) {
  217. printf("You expect SMODE present, but SMODE is not present, will not run this example!\r\n");
  218. printf("You can rebuild and run this example with extra make option XLCFG_SMODE=0 if SMODE not present!\r\n");
  219. return 0;
  220. }
  221. Exception_Register_EXC_S(IlleIns_EXCn, (unsigned long)smode_exception_handler);
  222. Exception_Register_EXC_S(UmodeEcall_EXCn, (unsigned long)smode_exception_handler);
  223. printf("Drop to S-Mode now\n\r");
  224. /* Drop to S mode */
  225. __switch_mode(PRV_S, smode_sp, supervisor_mode_entry_point);
  226. #else
  227. printf("Drop to U-Mode now\n\r");
  228. /* Drop to U mode */
  229. __switch_mode(PRV_U, umode_sp, user_mode_entry_point);
  230. #endif
  231. #else
  232. printf("__PMP_PRESENT must be defined as 1 in <Device>.h!\r\n");
  233. #endif
  234. return 0;
  235. }