syscalls.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /* Copyright 2018 Canaan Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. /* Enable kernel-mode log API */
  16. #include <errno.h>
  17. #include <limits.h>
  18. #include <machine/syscall.h>
  19. #include <stdarg.h>
  20. #include <stdbool.h>
  21. #include <stdint.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <sys/time.h>
  27. #include <sys/unistd.h>
  28. #include "atomic.h"
  29. #include "clint.h"
  30. #include "dump.h"
  31. #include "fpioa.h"
  32. #include "interrupt.h"
  33. #include "syscalls.h"
  34. #include "sysctl.h"
  35. #include "syslog.h"
  36. #include "util.h"
  37. #include "iomem.h"
  38. /**
  39. * @note System call list
  40. *
  41. * See also riscv-newlib/libgloss/riscv/syscalls.c
  42. *
  43. * | System call | Number |
  44. * |------------------|--------|
  45. * | SYS_exit | 93 |
  46. * | SYS_exit_group | 94 |
  47. * | SYS_getpid | 172 |
  48. * | SYS_kill | 129 |
  49. * | SYS_read | 63 |
  50. * | SYS_write | 64 |
  51. * | SYS_open | 1024 |
  52. * | SYS_openat | 56 |
  53. * | SYS_close | 57 |
  54. * | SYS_lseek | 62 |
  55. * | SYS_brk | 214 |
  56. * | SYS_link | 1025 |
  57. * | SYS_unlink | 1026 |
  58. * | SYS_mkdir | 1030 |
  59. * | SYS_chdir | 49 |
  60. * | SYS_getcwd | 17 |
  61. * | SYS_stat | 1038 |
  62. * | SYS_fstat | 80 |
  63. * | SYS_lstat | 1039 |
  64. * | SYS_fstatat | 79 |
  65. * | SYS_access | 1033 |
  66. * | SYS_faccessat | 48 |
  67. * | SYS_pread | 67 |
  68. * | SYS_pwrite | 68 |
  69. * | SYS_uname | 160 |
  70. * | SYS_getuid | 174 |
  71. * | SYS_geteuid | 175 |
  72. * | SYS_getgid | 176 |
  73. * | SYS_getegid | 177 |
  74. * | SYS_mmap | 222 |
  75. * | SYS_munmap | 215 |
  76. * | SYS_mremap | 216 |
  77. * | SYS_time | 1062 |
  78. * | SYS_getmainvars | 2011 |
  79. * | SYS_rt_sigaction | 134 |
  80. * | SYS_writev | 66 |
  81. * | SYS_gettimeofday | 169 |
  82. * | SYS_times | 153 |
  83. * | SYS_fcntl | 25 |
  84. * | SYS_getdents | 61 |
  85. * | SYS_dup | 23 |
  86. *
  87. */
  88. #ifndef UNUSED
  89. #define UNUSED(x) (void)(x)
  90. #endif
  91. static const char *TAG = "SYSCALL";
  92. extern char _heap_start[];
  93. extern char _heap_end[];
  94. char *_heap_cur = &_heap_start[0];
  95. char *_heap_line = &_heap_start[0];
  96. char *_ioheap_line = &_heap_end[0]-0x40000000;
  97. sys_putchar_t sys_putchar;
  98. sys_getchar_t sys_getchar;
  99. void sys_register_putchar(sys_putchar_t putchar)
  100. {
  101. sys_putchar = putchar;
  102. }
  103. void sys_register_getchar(sys_getchar_t getchar)
  104. {
  105. sys_getchar = getchar;
  106. }
  107. void sys_stdin_flush(void)
  108. {
  109. if(sys_getchar)
  110. while(sys_getchar() != EOF)
  111. continue;
  112. }
  113. void __attribute__((noreturn)) sys_exit(int code)
  114. {
  115. /* Read core id */
  116. unsigned long core_id = current_coreid();
  117. /* First print some diagnostic information. */
  118. LOGW(TAG, "sys_exit called by core %ld with 0x%lx\r\n", core_id, (uint64_t)code);
  119. while(1)
  120. continue;
  121. }
  122. static int sys_nosys(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n)
  123. {
  124. UNUSED(a3);
  125. UNUSED(a4);
  126. UNUSED(a5);
  127. LOGE(TAG, "Unsupported syscall %ld: a0=%lx, a1=%lx, a2=%lx!\r\n", n, a0, a1, a2);
  128. while(1)
  129. continue;
  130. return -ENOSYS;
  131. }
  132. static int sys_success(void)
  133. {
  134. return 0;
  135. }
  136. static size_t sys_brk(size_t pos)
  137. {
  138. uintptr_t res = 0;
  139. /**
  140. * brk() sets the end of the data segment to the value
  141. * specified by addr, when that value is reasonable, the system
  142. * has enough memory, and the process does not exceed its
  143. * maximum data size.
  144. *
  145. * sbrk() increments the program's data space by increment
  146. * bytes. Calling sbrk() with an increment of 0 can be used to
  147. * find the current location of the program break.
  148. *
  149. * uintptr_t brk(uintptr_t ptr);
  150. *
  151. * IN : regs[10] = ptr
  152. * OUT: regs[10] = ptr
  153. */
  154. /**
  155. * First call: Initialization brk pointer. newlib will pass
  156. * ptr = 0 when it is first called. In this case the address
  157. * _heap_start will be return.
  158. *
  159. * Call again: Adjust brk pointer. The ptr never equal with
  160. * 0. If ptr is below _heap_end, then allocate memory.
  161. * Otherwise throw out of memory error, return -1.
  162. */
  163. if(pos)
  164. {
  165. /* Call again */
  166. if((uintptr_t)pos > (uintptr_t)&_heap_end[0])
  167. {
  168. /* Memory out, return -ENOMEM */
  169. LOGE(TAG, "Out of memory\r\n");
  170. res = -ENOMEM;
  171. } else
  172. {
  173. if((uintptr_t)pos > (uintptr_t)_heap_line)
  174. {
  175. _heap_line = (char *)(uintptr_t)pos;
  176. if((uintptr_t)_heap_line-0x40000000 > (uintptr_t)_ioheap_line)
  177. {
  178. LOGE(TAG, "Out of memory!\r\n");
  179. while(1)
  180. ;
  181. }
  182. }
  183. /* Adjust brk pointer. */
  184. _heap_cur = (char *)(uintptr_t)pos;
  185. /* Return current address. */
  186. res = (uintptr_t)_heap_cur;
  187. }
  188. } else
  189. {
  190. /* First call, return initial address */
  191. res = (uintptr_t)&_heap_start[0];
  192. }
  193. return (size_t)res;
  194. }
  195. static ssize_t sys_write(int file, const void *ptr, size_t len)
  196. {
  197. ssize_t res = -EBADF;
  198. /**
  199. * Write to a file.
  200. *
  201. * ssize_t write(int file, const void *ptr, size_t len)
  202. *
  203. * IN : regs[10] = file, regs[11] = ptr, regs[12] = len
  204. * OUT: regs[10] = len
  205. */
  206. /* Get size to write */
  207. register size_t length = len;
  208. /* Get data pointer */
  209. register char *data = (char *)ptr;
  210. if(STDOUT_FILENO == file || STDERR_FILENO == file)
  211. {
  212. /* Write data */
  213. while(length-- > 0 && data != NULL)
  214. {
  215. if(sys_putchar)
  216. sys_putchar(*(data++));
  217. }
  218. /* Return the actual size written */
  219. res = len;
  220. } else
  221. {
  222. /* Not support yet */
  223. res = -ENOSYS;
  224. }
  225. return res;
  226. }
  227. static ssize_t sys_read(int file, void *ptr, size_t len)
  228. {
  229. ssize_t res = -EBADF;
  230. /**
  231. * Write from a file.
  232. *
  233. * ssize_t read(int file, void *ptr, size_t len)
  234. *
  235. * IN : regs[10] = file, regs[11] = ptr, regs[12] = len
  236. * OUT: regs[10] = len
  237. */
  238. /* Get size to read */
  239. register size_t length = len;
  240. /* Get data pointer */
  241. register char *data = (char *)ptr;
  242. /* Actual size to read */
  243. register size_t actual_length = 0;
  244. if(STDIN_FILENO == file)
  245. {
  246. /* Read data */
  247. actual_length = 0;
  248. while(length-- > 0 && data != NULL)
  249. {
  250. if(sys_getchar)
  251. {
  252. int getchar_result = sys_getchar();
  253. /* Get char until not EOF */
  254. while(getchar_result == EOF)
  255. getchar_result = sys_getchar();
  256. if(getchar_result != EOF)
  257. {
  258. /* Not EOF, read data to buffer */
  259. *(data++) = (char)getchar_result;
  260. actual_length++;
  261. /* Echo back this char to user */
  262. if(sys_putchar)
  263. sys_putchar((char)getchar_result);
  264. /* User press RETURN, break. This is the last step in stdin */
  265. if((char)getchar_result == '\r')
  266. break;
  267. if((char)getchar_result == '\n')
  268. break;
  269. } else
  270. {
  271. /* EOF, do nothing */
  272. }
  273. }
  274. }
  275. /* Return the actual size read */
  276. res = actual_length;
  277. } else
  278. {
  279. /* Not support yet */
  280. res = -ENOSYS;
  281. }
  282. return res;
  283. }
  284. static int sys_fstat(int file, struct stat *st)
  285. {
  286. int res = -EBADF;
  287. /**
  288. * Status of an open file. The sys/stat.h header file required
  289. * is
  290. * distributed in the include subdirectory for this C library.
  291. *
  292. * int fstat(int file, struct stat* st)
  293. *
  294. * IN : regs[10] = file, regs[11] = st
  295. * OUT: regs[10] = Upon successful completion, 0 shall be
  296. * returned.
  297. * Otherwise, -1 shall be returned and errno set to indicate
  298. * the error.
  299. */
  300. UNUSED(file);
  301. if(st != NULL)
  302. memset(st, 0, sizeof(struct stat));
  303. /* Return the result */
  304. res = -ENOSYS;
  305. /**
  306. * Note: This value will return to syscall wrapper, syscall
  307. * wrapper will set errno to ENOSYS and return -1
  308. */
  309. return res;
  310. }
  311. static int sys_close(int file)
  312. {
  313. int res = -EBADF;
  314. /**
  315. * Close a file.
  316. *
  317. * int close(int file)
  318. *
  319. * IN : regs[10] = file
  320. * OUT: regs[10] = Upon successful completion, 0 shall be
  321. * returned.
  322. * Otherwise, -1 shall be returned and errno set to indicate
  323. * the error.
  324. */
  325. UNUSED(file);
  326. /* Return the result */
  327. res = 0;
  328. return res;
  329. }
  330. static int sys_gettimeofday(struct timeval *tp, void *tzp)
  331. {
  332. /**
  333. * Get the current time. Only relatively correct.
  334. *
  335. * int gettimeofday(struct timeval *tp, void *tzp)
  336. *
  337. * IN : regs[10] = tp
  338. * OUT: regs[10] = Upon successful completion, 0 shall be
  339. * returned.
  340. * Otherwise, -1 shall be returned and errno set to indicate
  341. * the error.
  342. */
  343. UNUSED(tzp);
  344. if(tp != NULL)
  345. {
  346. uint64_t clint_usec = clint->mtime / (sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000000UL);
  347. tp->tv_sec = clint_usec / 1000000UL;
  348. tp->tv_usec = clint_usec % 1000000UL;
  349. }
  350. /* Return the result */
  351. return 0;
  352. }
  353. uintptr_t __attribute__((weak))
  354. handle_ecall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  355. {
  356. UNUSED(cause);
  357. UNUSED(fregs);
  358. enum syscall_id_e
  359. {
  360. SYS_ID_NOSYS,
  361. SYS_ID_SUCCESS,
  362. SYS_ID_EXIT,
  363. SYS_ID_BRK,
  364. SYS_ID_WRITE,
  365. SYS_ID_READ,
  366. SYS_ID_FSTAT,
  367. SYS_ID_CLOSE,
  368. SYS_ID_GETTIMEOFDAY,
  369. SYS_ID_MAX
  370. };
  371. static uintptr_t (*const syscall_table[])(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) =
  372. {
  373. [SYS_ID_NOSYS] = (void *)sys_nosys,
  374. [SYS_ID_SUCCESS] = (void *)sys_success,
  375. [SYS_ID_EXIT] = (void *)sys_exit,
  376. [SYS_ID_BRK] = (void *)sys_brk,
  377. [SYS_ID_WRITE] = (void *)sys_write,
  378. [SYS_ID_READ] = (void *)sys_read,
  379. [SYS_ID_FSTAT] = (void *)sys_fstat,
  380. [SYS_ID_CLOSE] = (void *)sys_close,
  381. [SYS_ID_GETTIMEOFDAY] = (void *)sys_gettimeofday,
  382. };
  383. #if defined(__GNUC__)
  384. #pragma GCC diagnostic ignored "-Woverride-init"
  385. #endif
  386. static const uint8_t syscall_id_table[0x100] =
  387. {
  388. [0x00 ... 0xFF] = SYS_ID_NOSYS,
  389. [0xFF &
  390. SYS_exit] = SYS_ID_EXIT,
  391. [0xFF &
  392. SYS_exit_group] = SYS_ID_EXIT,
  393. [0xFF &
  394. SYS_getpid] = SYS_ID_NOSYS,
  395. [0xFF &
  396. SYS_kill] = SYS_ID_NOSYS,
  397. [0xFF &
  398. SYS_read] = SYS_ID_READ,
  399. [0xFF &
  400. SYS_write] = SYS_ID_WRITE,
  401. [0xFF &
  402. SYS_open] = SYS_ID_NOSYS,
  403. [0xFF &
  404. SYS_openat] = SYS_ID_NOSYS,
  405. [0xFF &
  406. SYS_close] = SYS_ID_CLOSE,
  407. [0xFF &
  408. SYS_lseek] = SYS_ID_NOSYS,
  409. [0xFF &
  410. SYS_brk] = SYS_ID_BRK,
  411. [0xFF &
  412. SYS_link] = SYS_ID_NOSYS,
  413. [0xFF &
  414. SYS_unlink] = SYS_ID_NOSYS,
  415. [0xFF &
  416. SYS_mkdir] = SYS_ID_NOSYS,
  417. [0xFF &
  418. SYS_chdir] = SYS_ID_NOSYS,
  419. [0xFF &
  420. SYS_getcwd] = SYS_ID_NOSYS,
  421. [0xFF &
  422. SYS_stat] = SYS_ID_NOSYS,
  423. [0xFF &
  424. SYS_fstat] = SYS_ID_FSTAT,
  425. [0xFF &
  426. SYS_lstat] = SYS_ID_NOSYS,
  427. [0xFF &
  428. SYS_fstatat] = SYS_ID_NOSYS,
  429. [0xFF &
  430. SYS_access] = SYS_ID_NOSYS,
  431. [0xFF &
  432. SYS_faccessat] = SYS_ID_NOSYS,
  433. [0xFF &
  434. SYS_pread] = SYS_ID_NOSYS,
  435. [0xFF &
  436. SYS_pwrite] = SYS_ID_NOSYS,
  437. [0xFF &
  438. SYS_uname] = SYS_ID_NOSYS,
  439. [0xFF &
  440. SYS_getuid] = SYS_ID_NOSYS,
  441. [0xFF &
  442. SYS_geteuid] = SYS_ID_NOSYS,
  443. [0xFF &
  444. SYS_getgid] = SYS_ID_NOSYS,
  445. [0xFF &
  446. SYS_getegid] = SYS_ID_NOSYS,
  447. [0xFF &
  448. SYS_mmap] = SYS_ID_NOSYS,
  449. [0xFF &
  450. SYS_munmap] = SYS_ID_NOSYS,
  451. [0xFF &
  452. SYS_mremap] = SYS_ID_NOSYS,
  453. [0xFF &
  454. SYS_time] = SYS_ID_NOSYS,
  455. [0xFF &
  456. SYS_getmainvars] = SYS_ID_NOSYS,
  457. [0xFF &
  458. SYS_rt_sigaction] = SYS_ID_NOSYS,
  459. [0xFF &
  460. SYS_writev] = SYS_ID_NOSYS,
  461. [0xFF &
  462. SYS_gettimeofday] = SYS_ID_GETTIMEOFDAY,
  463. [0xFF &
  464. SYS_times] = SYS_ID_NOSYS,
  465. [0xFF &
  466. SYS_fcntl] = SYS_ID_NOSYS,
  467. [0xFF &
  468. SYS_getdents] = SYS_ID_NOSYS,
  469. [0xFF &
  470. SYS_dup] = SYS_ID_NOSYS,
  471. };
  472. #if defined(__GNUC__)
  473. #pragma GCC diagnostic warning "-Woverride-init"
  474. #endif
  475. regs[10] = syscall_table[syscall_id_table[0xFF & regs[17]]](
  476. regs[10], /* a0 */
  477. regs[11], /* a1 */
  478. regs[12], /* a2 */
  479. regs[13], /* a3 */
  480. regs[14], /* a4 */
  481. regs[15], /* a5 */
  482. regs[17] /* n */
  483. );
  484. return epc + 4;
  485. }
  486. uintptr_t __attribute__((weak, alias("handle_ecall")))
  487. handle_ecall_u(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
  488. uintptr_t __attribute__((weak, alias("handle_ecall")))
  489. handle_ecall_h(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
  490. uintptr_t __attribute__((weak, alias("handle_ecall")))
  491. handle_ecall_s(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
  492. uintptr_t __attribute__((weak, alias("handle_ecall")))
  493. handle_ecall_m(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
  494. uintptr_t __attribute__((weak))
  495. handle_misaligned_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  496. {
  497. dump_core("misaligned fetch", cause, epc, regs, fregs);
  498. sys_exit(1337);
  499. return epc;
  500. }
  501. uintptr_t __attribute__((weak))
  502. handle_fault_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  503. {
  504. dump_core("fault fetch", cause, epc, regs, fregs);
  505. sys_exit(1337);
  506. return epc;
  507. }
  508. uintptr_t __attribute__((weak))
  509. handle_illegal_instruction(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  510. {
  511. dump_core("illegal instruction", cause, epc, regs, fregs);
  512. sys_exit(1337);
  513. return epc;
  514. }
  515. uintptr_t __attribute__((weak))
  516. handle_breakpoint(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  517. {
  518. dump_core("breakpoint", cause, epc, regs, fregs);
  519. sys_exit(1337);
  520. return epc;
  521. }
  522. uintptr_t __attribute__((weak))
  523. handle_misaligned_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  524. {
  525. dump_core("misaligned load", cause, epc, regs, fregs);
  526. /* notice this function only support 16bit or 32bit instruction */
  527. bool compressed = (*(unsigned short *)epc & 3) != 3;
  528. bool fpu = 0; /* load to fpu ? */
  529. uintptr_t addr = 0; /* src addr */
  530. uint8_t src = 0; /* src register */
  531. uint8_t dst = 0; /* dst register */
  532. uint8_t len = 0; /* data length */
  533. int offset = 0; /* addr offset to addr in reg */
  534. bool unsigned_ = 0; /* unsigned */
  535. uint64_t data_load = 0; /* real data load */
  536. if(compressed)
  537. {
  538. /* compressed instruction should not get this fault. */
  539. goto on_error;
  540. } else
  541. {
  542. uint32_t instruct = *(uint32_t *)epc;
  543. uint8_t opcode = instruct & 0x7F;
  544. dst = (instruct >> 7) & 0x1F;
  545. len = (instruct >> 12) & 3;
  546. unsigned_ = (instruct >> 14) & 1;
  547. src = (instruct >> 15) & 0x1F;
  548. offset = (instruct >> 20);
  549. len = 1 << len;
  550. switch(opcode)
  551. {
  552. case 3: /* load */
  553. break;
  554. case 7: /* fpu load */
  555. fpu = 1;
  556. break;
  557. default:
  558. goto on_error;
  559. }
  560. }
  561. if(offset >> 11)
  562. offset = -((offset & 0x3FF) + 1);
  563. addr = (uint64_t)((uint64_t)regs[src] + offset);
  564. for(int i = 0; i < len; ++i)
  565. data_load |= ((uint64_t) * ((uint8_t *)addr + i)) << (8 * i);
  566. if(!unsigned_ & !fpu)
  567. {
  568. /* adjust sign */
  569. switch(len)
  570. {
  571. case 1:
  572. data_load = (uint64_t)(int64_t)((int8_t)data_load);
  573. break;
  574. case 2:
  575. data_load = (uint64_t)(int64_t)((int16_t)data_load);
  576. break;
  577. case 4:
  578. data_load = (uint64_t)(int64_t)((int32_t)data_load);
  579. break;
  580. default:
  581. break;
  582. }
  583. }
  584. if(fpu)
  585. fregs[dst] = data_load;
  586. else
  587. regs[dst] = data_load;
  588. LOGV(TAG, "misaligned load recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,signed:%1d,float:%1d", (uint64_t)epc, len, (uint64_t)addr, dst, data_load, !unsigned_, fpu);
  589. return epc + (compressed ? 2 : 4);
  590. on_error:
  591. dump_core("misaligned load", cause, epc, regs, fregs);
  592. sys_exit(1337);
  593. return epc;
  594. }
  595. uintptr_t __attribute__((weak))
  596. handle_fault_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  597. {
  598. dump_core("fault load", cause, epc, regs, fregs);
  599. sys_exit(1337);
  600. return epc;
  601. }
  602. uintptr_t __attribute__((weak))
  603. handle_misaligned_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  604. {
  605. dump_core("misaligned store", cause, epc, regs, fregs);
  606. /* notice this function only support 16bit or 32bit instruction */
  607. bool compressed = (*(unsigned short *)epc & 3) != 3;
  608. bool fpu = 0; /* store to fpu*/
  609. uintptr_t addr = 0; /* src addr*/
  610. uint8_t src = 0; /* src register*/
  611. uint8_t dst = 0; /* dst register*/
  612. uint8_t len = 0; /* data length*/
  613. int offset = 0; /* addr offset to addr in reg*/
  614. uint64_t data_store = 0; /* real data store*/
  615. if(compressed)
  616. {
  617. /* compressed instruction should not get this fault. */
  618. goto on_error;
  619. } else
  620. {
  621. uint32_t instruct = *(uint32_t *)epc;
  622. uint8_t opcode = instruct & 0x7F;
  623. len = (instruct >> 12) & 7;
  624. dst = (instruct >> 15) & 0x1F;
  625. src = (instruct >> 20) & 0x1F;
  626. offset = ((instruct >> 7) & 0x1F) | ((instruct >> 20) & 0xFE0);
  627. len = 1 << len;
  628. switch(opcode)
  629. {
  630. case 0x23: /* store */
  631. break;
  632. case 0x27: /* fpu store */
  633. fpu = 1;
  634. break;
  635. default:
  636. goto on_error;
  637. }
  638. }
  639. if(offset >> 11)
  640. offset = -((offset & 0x3FF) + 1);
  641. addr = (uint64_t)((uint64_t)regs[dst] + offset);
  642. if(fpu)
  643. data_store = fregs[src];
  644. else
  645. data_store = regs[src];
  646. for(int i = 0; i < len; ++i)
  647. *((uint8_t *)addr + i) = (data_store >> (i * 8)) & 0xFF;
  648. LOGV(TAG, "misaligned store recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,float:%1d", (uint64_t)epc, len, (uint64_t)addr, src, data_store, fpu);
  649. return epc + (compressed ? 2 : 4);
  650. on_error:
  651. dump_core("misaligned store", cause, epc, regs, fregs);
  652. sys_exit(1337);
  653. return epc;
  654. }
  655. uintptr_t __attribute__((weak))
  656. handle_fault_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  657. {
  658. dump_core("fault store", cause, epc, regs, fregs);
  659. sys_exit(1337);
  660. return epc;
  661. }
  662. uintptr_t handle_syscall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
  663. {
  664. static uintptr_t (*const cause_table[])(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) =
  665. {
  666. [CAUSE_MISALIGNED_FETCH] = handle_misaligned_fetch,
  667. [CAUSE_FAULT_FETCH] = handle_fault_fetch,
  668. [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction,
  669. [CAUSE_BREAKPOINT] = handle_breakpoint,
  670. [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load,
  671. [CAUSE_FAULT_LOAD] = handle_fault_load,
  672. [CAUSE_MISALIGNED_STORE] = handle_misaligned_store,
  673. [CAUSE_FAULT_STORE] = handle_fault_store,
  674. [CAUSE_USER_ECALL] = handle_ecall_u,
  675. [CAUSE_SUPERVISOR_ECALL] = handle_ecall_h,
  676. [CAUSE_HYPERVISOR_ECALL] = handle_ecall_s,
  677. [CAUSE_MACHINE_ECALL] = handle_ecall_m,
  678. };
  679. return cause_table[cause](cause, epc, regs, fregs);
  680. }
  681. size_t get_free_heap_size(void)
  682. {
  683. return (size_t)iomem_unused();
  684. }