syscall.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /* we use l1 and l2 cache ops to help stability. */
  2. #include "u.h"
  3. #include "../port/lib.h"
  4. #include "mem.h"
  5. #include "dat.h"
  6. #include "fns.h"
  7. #include "../port/error.h"
  8. #include "../port/systab.h"
  9. #include <tos.h>
  10. #include "ureg.h"
  11. #include "arm.h"
  12. enum {
  13. Psrsysbits = PsrMask | PsrDfiq | PsrDirq | PsrDasabt | PsrMbz,
  14. };
  15. typedef struct {
  16. uintptr ip;
  17. Ureg* arg0;
  18. char* arg1;
  19. char msg[ERRMAX];
  20. Ureg* old;
  21. Ureg ureg;
  22. } NFrame;
  23. /*
  24. * Return user to state before notify()
  25. */
  26. static void
  27. noted(Ureg* cur, uintptr arg0)
  28. {
  29. NFrame *nf;
  30. Ureg *nur;
  31. qlock(&up->debug);
  32. if(arg0 != NRSTR && !up->notified){
  33. qunlock(&up->debug);
  34. pprint("call to noted() when not notified\n");
  35. pexit("Suicide", 0);
  36. }
  37. up->notified = 0;
  38. fpunoted();
  39. nf = up->ureg;
  40. /* sanity clause */
  41. if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
  42. qunlock(&up->debug);
  43. pprint("bad ureg in noted %#p\n", nf);
  44. pexit("Suicide", 0);
  45. }
  46. /* don't let user change system flags */
  47. nur = &nf->ureg;
  48. nur->psr &= Psrsysbits;
  49. nur->psr |= cur->psr & ~Psrsysbits;
  50. memmove(cur, nur, sizeof(Ureg));
  51. switch((int)arg0){
  52. case NCONT:
  53. case NRSTR:
  54. if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
  55. qunlock(&up->debug);
  56. pprint("suicide: trap in noted\n");
  57. pexit("Suicide", 0);
  58. }
  59. up->ureg = nf->old;
  60. qunlock(&up->debug);
  61. break;
  62. case NSAVE:
  63. if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
  64. qunlock(&up->debug);
  65. pprint("suicide: trap in noted\n");
  66. pexit("Suicide", 0);
  67. }
  68. qunlock(&up->debug);
  69. splhi();
  70. nf->arg1 = nf->msg;
  71. nf->arg0 = &nf->ureg;
  72. nf->ip = 0;
  73. cur->sp = PTR2UINT(nf);
  74. break;
  75. default:
  76. pprint("unknown noted arg %#p\n", arg0);
  77. up->lastnote.flag = NDebug;
  78. /*FALLTHROUGH*/
  79. case NDFLT:
  80. if(up->lastnote.flag == NDebug){
  81. qunlock(&up->debug);
  82. pprint("suicide: %s\n", up->lastnote.msg);
  83. }
  84. else
  85. qunlock(&up->debug);
  86. pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
  87. }
  88. }
  89. /*
  90. * Call user, if necessary, with note.
  91. * Pass user the Ureg struct and the note on his stack.
  92. */
  93. int
  94. notify(Ureg* ureg)
  95. {
  96. int l;
  97. Note *n;
  98. u32int s;
  99. uintptr sp;
  100. NFrame *nf;
  101. if(up->procctl)
  102. procctl(up);
  103. if(up->nnote == 0)
  104. return 0;
  105. fpunotify(ureg);
  106. s = spllo();
  107. qlock(&up->debug);
  108. up->notepending = 0;
  109. n = &up->note[0];
  110. if(strncmp(n->msg, "sys:", 4) == 0){
  111. l = strlen(n->msg);
  112. if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */
  113. l = ERRMAX-23;
  114. snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
  115. }
  116. if(n->flag != NUser && (up->notified || up->notify == 0)){
  117. if(n->flag == NDebug)
  118. pprint("suicide: %s\n", n->msg);
  119. qunlock(&up->debug);
  120. pexit(n->msg, n->flag != NDebug);
  121. }
  122. if(up->notified){
  123. qunlock(&up->debug);
  124. splhi();
  125. return 0;
  126. }
  127. if(up->notify == nil){
  128. qunlock(&up->debug);
  129. pexit(n->msg, n->flag != NDebug);
  130. }
  131. if(!okaddr(PTR2UINT(up->notify), 1, 0)){
  132. pprint("suicide: notify function address %#p\n", up->notify);
  133. qunlock(&up->debug);
  134. pexit("Suicide", 0);
  135. }
  136. sp = ureg->sp - sizeof(NFrame);
  137. if(!okaddr(sp, sizeof(NFrame), 1)){
  138. qunlock(&up->debug);
  139. pprint("suicide: notify stack address %#p\n", sp);
  140. pexit("Suicide", 0);
  141. }
  142. nf = UINT2PTR(sp);
  143. memmove(&nf->ureg, ureg, sizeof(Ureg));
  144. nf->old = up->ureg;
  145. up->ureg = nf;
  146. memmove(nf->msg, up->note[0].msg, ERRMAX);
  147. nf->arg1 = nf->msg;
  148. nf->arg0 = &nf->ureg;
  149. nf->ip = 0;
  150. ureg->sp = sp;
  151. ureg->pc = PTR2UINT(up->notify);
  152. up->notified = 1;
  153. up->nnote--;
  154. memmove(&up->lastnote, &up->note[0], sizeof(Note));
  155. memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
  156. qunlock(&up->debug);
  157. splx(s);
  158. l1cache->wb(); /* is this needed? */
  159. return 1;
  160. }
  161. void
  162. syscall(Ureg* ureg)
  163. {
  164. char *e;
  165. u32int s;
  166. ulong sp;
  167. long ret;
  168. int i, scallnr;
  169. vlong startns, stopns;
  170. if(!userureg(ureg))
  171. panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
  172. ureg->pc, ureg->r14, ureg->psr);
  173. cycles(&up->kentry);
  174. m->syscall++;
  175. up->insyscall = 1;
  176. up->pc = ureg->pc;
  177. up->dbgreg = ureg;
  178. scallnr = ureg->r0;
  179. up->scallnr = scallnr;
  180. if(scallnr == RFORK)
  181. fpusysrfork(ureg);
  182. spllo();
  183. sp = ureg->sp;
  184. if(up->procctl == Proc_tracesyscall){
  185. /*
  186. * Redundant validaddr. Do we care?
  187. * Tracing syscalls is not exactly a fast path...
  188. * Beware, validaddr currently does a pexit rather
  189. * than an error if there's a problem; that might
  190. * change in the future.
  191. */
  192. if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
  193. validaddr(sp, sizeof(Sargs)+BY2WD, 0);
  194. syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
  195. up->procctl = Proc_stopme;
  196. procctl(up);
  197. if (up->syscalltrace)
  198. free(up->syscalltrace);
  199. up->syscalltrace = nil;
  200. }
  201. up->nerrlab = 0;
  202. ret = -1;
  203. startns = todget(nil);
  204. l1cache->wb(); /* system is more stable with this */
  205. if(!waserror()){
  206. if(scallnr >= nsyscall){
  207. pprint("bad sys call number %d pc %#lux\n",
  208. scallnr, ureg->pc);
  209. postnote(up, 1, "sys: bad sys call", NDebug);
  210. error(Ebadarg);
  211. }
  212. if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
  213. validaddr(sp, sizeof(Sargs)+BY2WD, 0);
  214. up->s = *((Sargs*)(sp+BY2WD));
  215. up->psstate = sysctab[scallnr];
  216. /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
  217. ret = systab[scallnr](up->s.args);
  218. poperror();
  219. }else{
  220. /* failure: save the error buffer for errstr */
  221. e = up->syserrstr;
  222. up->syserrstr = up->errstr;
  223. up->errstr = e;
  224. }
  225. if(up->nerrlab){
  226. print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
  227. for(i = 0; i < NERR; i++)
  228. print("sp=%#p pc=%#p\n",
  229. up->errlab[i].sp, up->errlab[i].pc);
  230. panic("error stack");
  231. }
  232. /*
  233. * Put return value in frame. On the x86 the syscall is
  234. * just another trap and the return value from syscall is
  235. * ignored. On other machines the return value is put into
  236. * the results register by caller of syscall.
  237. */
  238. ureg->r0 = ret;
  239. if(up->procctl == Proc_tracesyscall){
  240. stopns = todget(nil);
  241. up->procctl = Proc_stopme;
  242. sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
  243. s = splhi();
  244. procctl(up);
  245. splx(s);
  246. if(up->syscalltrace)
  247. free(up->syscalltrace);
  248. up->syscalltrace = nil;
  249. }
  250. up->insyscall = 0;
  251. up->psstate = 0;
  252. if(scallnr == NOTED)
  253. noted(ureg, *(ulong*)(sp+BY2WD));
  254. splhi();
  255. if(scallnr != RFORK && (up->procctl || up->nnote))
  256. notify(ureg);
  257. l1cache->wb(); /* system is more stable with this */
  258. /* if we delayed sched because we held a lock, sched now */
  259. if(up->delaysched){
  260. sched();
  261. splhi();
  262. }
  263. kexit(ureg);
  264. }
  265. long
  266. execregs(ulong entry, ulong ssize, ulong nargs)
  267. {
  268. ulong *sp;
  269. Ureg *ureg;
  270. sp = (ulong*)(USTKTOP - ssize);
  271. *--sp = nargs;
  272. ureg = up->dbgreg;
  273. // memset(ureg, 0, 15*sizeof(ulong));
  274. ureg->r13 = (ulong)sp;
  275. ureg->pc = entry;
  276. //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
  277. allcache->wbse(ureg, sizeof *ureg); /* is this needed? */
  278. /*
  279. * return the address of kernel/user shared data
  280. * (e.g. clock stuff)
  281. */
  282. return USTKTOP-sizeof(Tos);
  283. }
  284. void
  285. sysprocsetup(Proc* p)
  286. {
  287. fpusysprocsetup(p);
  288. }
  289. /*
  290. * Craft a return frame which will cause the child to pop out of
  291. * the scheduler in user mode with the return register zero. Set
  292. * pc to point to a l.s return function.
  293. */
  294. void
  295. forkchild(Proc *p, Ureg *ureg)
  296. {
  297. Ureg *cureg;
  298. p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
  299. p->sched.pc = (ulong)forkret;
  300. cureg = (Ureg*)(p->sched.sp);
  301. memmove(cureg, ureg, sizeof(Ureg));
  302. /* syscall returns 0 for child */
  303. cureg->r0 = 0;
  304. /* Things from bottom of syscall which were never executed */
  305. p->psstate = 0;
  306. p->insyscall = 0;
  307. fpusysrforkchild(p, cureg, up);
  308. }