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