syscall.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "../../libc/9syscall/sys.h"
  8. #include <tos.h>
  9. #include "amd64.h"
  10. #include "ureg.h"
  11. typedef struct {
  12. uintptr ip;
  13. Ureg* arg0;
  14. char* arg1;
  15. char msg[ERRMAX];
  16. Ureg* old;
  17. Ureg ureg;
  18. } NFrame;
  19. /*
  20. * Return user to state before notify()
  21. */
  22. void
  23. noted(Ureg* cur, uintptr arg0)
  24. {
  25. NFrame *nf;
  26. Note note;
  27. Ureg *nur;
  28. qlock(&up->debug);
  29. if(arg0 != NRSTR && !up->notified){
  30. qunlock(&up->debug);
  31. pprint("suicide: call to noted when not notified\n");
  32. pexit("Suicide", 0);
  33. }
  34. up->notified = 0;
  35. fpunoted();
  36. nf = up->ureg;
  37. /* sanity clause */
  38. if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
  39. qunlock(&up->debug);
  40. pprint("suicide: bad ureg %#p in noted\n", nf);
  41. pexit("Suicide", 0);
  42. }
  43. /*
  44. * Check the segment selectors are all valid.
  45. */
  46. nur = &nf->ureg;
  47. if(nur->cs != SSEL(SiUCS, SsRPL3) || nur->ss != SSEL(SiUDS, SsRPL3)
  48. || nur->ds != SSEL(SiUDS, SsRPL3) || nur->es != SSEL(SiUDS, SsRPL3)
  49. || nur->gs != SSEL(SiUDS, SsRPL3)){
  50. qunlock(&up->debug);
  51. pprint("suicide: bad segment selector in noted\n");
  52. pexit("Suicide", 0);
  53. }
  54. /* don't let user change system flags */
  55. nur->flags &= (Of|Df|Sf|Zf|Af|Pf|Cf);
  56. nur->flags |= cur->flags & ~(Of|Df|Sf|Zf|Af|Pf|Cf);
  57. memmove(cur, nur, sizeof(Ureg));
  58. switch((int)arg0){
  59. case NCONT:
  60. case NRSTR:
  61. if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
  62. qunlock(&up->debug);
  63. pprint("suicide: trap in noted pc=%#p sp=%#p\n",
  64. nur->ip, nur->sp);
  65. pexit("Suicide", 0);
  66. }
  67. up->ureg = nf->old;
  68. qunlock(&up->debug);
  69. break;
  70. case NSAVE:
  71. if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
  72. qunlock(&up->debug);
  73. pprint("suicide: trap in noted pc=%#p sp=%#p\n",
  74. nur->ip, nur->sp);
  75. pexit("Suicide", 0);
  76. }
  77. qunlock(&up->debug);
  78. splhi();
  79. nf->arg1 = nf->msg;
  80. nf->arg0 = &nf->ureg;
  81. cur->bp = PTR2UINT(nf->arg0);
  82. nf->ip = 0;
  83. cur->sp = PTR2UINT(nf);
  84. break;
  85. default:
  86. memmove(&note, &up->lastnote, sizeof(Note));
  87. qunlock(&up->debug);
  88. pprint("suicide: bad arg %#p in noted: %s\n", arg0, note.msg);
  89. pexit(note.msg, 0);
  90. break;
  91. case NDFLT:
  92. memmove(&note, &up->lastnote, sizeof(Note));
  93. qunlock(&up->debug);
  94. if(note.flag == NDebug)
  95. pprint("suicide: %s\n", note.msg);
  96. pexit(note.msg, note.flag != NDebug);
  97. break;
  98. }
  99. }
  100. /*
  101. * Call user, if necessary, with note.
  102. * Pass user the Ureg struct and the note on his stack.
  103. */
  104. int
  105. notify(Ureg* ureg)
  106. {
  107. int l;
  108. Mpl pl;
  109. Note note;
  110. uintptr sp;
  111. NFrame *nf;
  112. /*
  113. * Calls procctl splhi, see comment in procctl for the reasoning.
  114. */
  115. if(up->procctl)
  116. procctl(up);
  117. if(up->nnote == 0)
  118. return 0;
  119. fpunotify(ureg);
  120. pl = spllo();
  121. qlock(&up->debug);
  122. up->notepending = 0;
  123. memmove(&note, &up->note[0], sizeof(Note));
  124. if(strncmp(note.msg, "sys:", 4) == 0){
  125. l = strlen(note.msg);
  126. if(l > ERRMAX-sizeof(" pc=0x0123456789abcdef"))
  127. l = ERRMAX-sizeof(" pc=0x0123456789abcdef");
  128. sprint(note.msg+l, " pc=%#p", ureg->ip);
  129. }
  130. if(note.flag != NUser && (up->notified || up->notify == nil)){
  131. qunlock(&up->debug);
  132. if(note.flag == NDebug)
  133. pprint("suicide: %s\n", note.msg);
  134. pexit(note.msg, note.flag != NDebug);
  135. }
  136. if(up->notified){
  137. qunlock(&up->debug);
  138. splhi();
  139. return 0;
  140. }
  141. if(up->notify == nil){
  142. qunlock(&up->debug);
  143. pexit(note.msg, note.flag != NDebug);
  144. }
  145. if(!okaddr(PTR2UINT(up->notify), sizeof(ureg->ip), 0)){
  146. qunlock(&up->debug);
  147. pprint("suicide: bad function address %#p in notify\n",
  148. up->notify);
  149. pexit("Suicide", 0);
  150. }
  151. sp = ureg->sp;
  152. sp -= 128; /* debugging: preserve context causing problem */
  153. sp -= sizeof(NFrame);
  154. if(!okaddr(sp, sizeof(NFrame), 1)){
  155. qunlock(&up->debug);
  156. pprint("suicide: bad stack address %#p in notify\n", sp);
  157. pexit("Suicide", 0);
  158. }
  159. nf = UINT2PTR(sp);
  160. memmove(&nf->ureg, ureg, sizeof(Ureg));
  161. nf->old = up->ureg;
  162. up->ureg = nf; /* actually the NFrame, for noted */
  163. memmove(nf->msg, note.msg, ERRMAX);
  164. nf->arg1 = nf->msg;
  165. nf->arg0 = &nf->ureg;
  166. ureg->bp = PTR2UINT(nf->arg0);
  167. nf->ip = 0;
  168. ureg->sp = sp;
  169. ureg->ip = PTR2UINT(up->notify);
  170. up->notified = 1;
  171. up->nnote--;
  172. memmove(&up->lastnote, &note, sizeof(Note));
  173. memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
  174. qunlock(&up->debug);
  175. splx(pl);
  176. return 1;
  177. }
  178. void
  179. noerrorsleft(void)
  180. {
  181. int i;
  182. if(up->nerrlab){
  183. /* NIX processes will have a waserror in their handler */
  184. if(up->ac != nil && up->nerrlab == 1)
  185. return;
  186. print("bad errstack: %d extra\n", up->nerrlab);
  187. for(i = 0; i < NERR; i++)
  188. print("sp=%#p pc=%#p\n",
  189. up->errlab[i].sp, up->errlab[i].pc);
  190. panic("error stack");
  191. }
  192. }
  193. int
  194. badsyscall(int scallnr)
  195. {
  196. if(scallnr >= nsyscall || systab[scallnr].f == nil)
  197. return 1;
  198. return 0;
  199. }
  200. void
  201. traceend(int scallnr, uintptr sp, Ar0 *ar0, vlong startns, vlong stopns)
  202. {
  203. int s;
  204. up->procctl = Proc_stopme;
  205. sysretfmt(scallnr, (va_list)(sp+BY2SE), ar0, startns, stopns);
  206. s = splhi();
  207. procctl(up);
  208. splx(s);
  209. if(up->syscalltrace)
  210. free(up->syscalltrace);
  211. up->syscalltrace = nil;
  212. }
  213. /* special case: leaving sysrfork as a child. We consider 0 time to have passed.
  214. * always return 0.
  215. */
  216. void
  217. rforktraceend(void)
  218. {
  219. traceend(RFORK, 0, nil, 0, 0);
  220. }
  221. /* it should be unsigned. FIXME */
  222. void
  223. syscall(int badscallnr, Ureg* ureg)
  224. {
  225. unsigned int scallnr = (u8int) badscallnr;
  226. char *e;
  227. uintptr sp, *args;
  228. int s;
  229. vlong startns, stopns;
  230. Ar0 ar0;
  231. static Ar0 zar0;
  232. if(!userureg(ureg))
  233. panic("syscall: cs %#llux\n", ureg->cs);
  234. cycles(&up->kentry);
  235. m->syscall++;
  236. up->nsyscall++;
  237. up->nqsyscall++;
  238. up->insyscall = 1;
  239. up->pc = ureg->ip;
  240. up->dbgreg = ureg;
  241. sp = ureg->sp;
  242. startns = 0;
  243. if(up->procctl == Proc_tracesyscall){
  244. /*
  245. * Redundant validaddr. Do we care?
  246. * Tracing syscalls is not exactly a fast path...
  247. * Beware, validaddr currently does a pexit rather
  248. * than an error if there's a problem; that might
  249. * change in the future.
  250. */
  251. if(sp < (USTKTOP-BIGPGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE))
  252. validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0);
  253. syscallfmt(scallnr, (va_list)(sp+BY2SE));
  254. up->procctl = Proc_stopme;
  255. procctl(up);
  256. if(up->syscalltrace)
  257. free(up->syscalltrace);
  258. up->syscalltrace = nil;
  259. startns = todget(nil);
  260. }
  261. up->scallnr = scallnr;
  262. if(scallnr == RFORK)
  263. fpusysrfork(ureg);
  264. spllo();
  265. sp = ureg->sp;
  266. up->nerrlab = 0;
  267. ar0 = zar0;
  268. if(!waserror()){
  269. if(badsyscall(scallnr)){
  270. pprint("bad sys call number %d pc %#llux\n",
  271. scallnr, ureg->ip);
  272. postnote(up, 1, "sys: bad sys call", NDebug);
  273. error(Ebadarg);
  274. }
  275. args = (uintptr *)up->arg;
  276. args[0] = ureg->di;
  277. args[1] = ureg->si;
  278. args[2] = ureg->dx;
  279. args[3] = ureg->r10;
  280. args[4] = ureg->r8;
  281. up->psstate = systab[scallnr].n;
  282. systab[scallnr].f(&ar0, (va_list)up->arg);
  283. if(scallnr == SYSR1){
  284. /*
  285. * BUG: must go when ron binaries go.
  286. * NIX: Returning from execac().
  287. * This means that the process is back to the
  288. * time sharing core. However, the process did
  289. * already return from the system call, when dispatching
  290. * the user code to the AC. The only thing left is to
  291. * return. The user registers should be ok, because
  292. * up->dbgreg has been the user context for the process.
  293. */
  294. return;
  295. }
  296. poperror();
  297. }
  298. else{
  299. char *syscallname = "INVALID";
  300. ar0.i = -1;
  301. /* failure: save the error buffer for errstr */
  302. e = up->syserrstr;
  303. up->syserrstr = up->errstr;
  304. up->errstr = e;
  305. /* this used to panic the kernel on a bad system call # */
  306. if(!badsyscall(scallnr)){
  307. syscallname = systab[scallnr].n;
  308. ar0 = systab[scallnr].r;
  309. }
  310. if(DBGFLG && up->pid == 1)
  311. iprint("%s: syscall %s error %s\n",
  312. up->text, syscallname, up->syserrstr);
  313. }
  314. /*
  315. * NIX: for the execac() syscall, what follows is done within
  316. * the system call, because it never returns.
  317. */
  318. noerrorsleft();
  319. /*
  320. * Put return value in frame.
  321. */
  322. ureg->ax = ar0.p;
  323. if(up->procctl == Proc_tracesyscall){
  324. stopns = todget(nil);
  325. traceend(scallnr, sp, &ar0, startns, stopns);
  326. }else if(up->procctl == Proc_totc || up->procctl == Proc_toac)
  327. procctl(up);
  328. up->insyscall = 0;
  329. up->psstate = 0;
  330. if(scallnr == NOTED)
  331. noted(ureg, *(uintptr*)(sp+BY2SE));
  332. splhi();
  333. if(scallnr != RFORK && (up->procctl || up->nnote))
  334. notify(ureg);
  335. /* if we delayed sched because we held a lock, sched now */
  336. if(up->delaysched){
  337. sched();
  338. splhi();
  339. }
  340. kexit(ureg);
  341. }
  342. uintptr
  343. sysexecstack(uintptr stack, int argc)
  344. {
  345. /*
  346. * Given a current bottom-of-stack and a count
  347. * of pointer arguments to be pushed onto it followed
  348. * by an integer argument count, return a suitably
  349. * aligned new bottom-of-stack which will satisfy any
  350. * hardware stack-alignment contraints.
  351. * Rounding the stack down to be aligned with the
  352. * natural size of a pointer variable usually suffices,
  353. * but some architectures impose further restrictions,
  354. * e.g. 32-bit SPARC, where the stack must be 8-byte
  355. * aligned although pointers and integers are 32-bits.
  356. */
  357. USED(argc);
  358. return STACKALIGN(stack);
  359. }
  360. void*
  361. sysexecregs(uintptr entry, ulong ssize, ulong nargs)
  362. {
  363. uintptr *sp;
  364. Ureg *ureg;
  365. sp = (uintptr*)(USTKTOP - ssize);
  366. *--sp = nargs;
  367. ureg = up->dbgreg;
  368. ureg->sp = PTR2UINT(sp);
  369. ureg->ip = entry;
  370. ureg->type = 64; /* fiction for acid */
  371. /*
  372. * return the address of kernel/user shared data
  373. * (e.g. clock stuff)
  374. */
  375. return UINT2PTR(USTKTOP-sizeof(Tos));
  376. }
  377. void
  378. sysprocsetup(Proc* p)
  379. {
  380. fpusysprocsetup(p);
  381. }
  382. void
  383. sysrforkchild(Proc* child, Proc* parent, void (*ret)(void), uintptr stack)
  384. {
  385. Ureg *cureg;
  386. /*
  387. * Add 3*BY2SE to the stack to account for
  388. * - the return PC
  389. * - trap's arguments (syscallnr, ureg)
  390. */
  391. child->sched.sp = PTR2UINT(child->kstack+KSTACK-(sizeof(Ureg)+3*BY2SE));
  392. child->sched.pc = PTR2UINT(ret);
  393. cureg = (Ureg*)(child->sched.sp+3*BY2SE);
  394. memmove(cureg, parent->dbgreg, sizeof(Ureg));
  395. if (stack)
  396. cureg->sp = stack;
  397. /* Things from bottom of syscall which were never executed */
  398. child->psstate = 0;
  399. child->insyscall = 0;
  400. fpusysrforkchild(child, parent);
  401. }