]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/syscall.c
kernel: add support for hardware watchpoints
[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(PTR2UINT(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 = PTR2UINT(nf);
81                 cur->r0 = PTR2UINT(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(PTR2UINT(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 = UINT2PTR(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 = PTR2UINT(up->notify);
167         ureg->r0 = PTR2UINT(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(!userureg(ureg))
190                 panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
191                         ureg->pc, ureg->r14, ureg->psr);
192
193         cycles(&up->kentry);
194
195         m->syscall++;
196         up->insyscall = 1;
197         up->pc = ureg->pc;
198         up->dbgreg = ureg;
199
200         if(up->procctl == Proc_tracesyscall){
201                 up->procctl = Proc_stopme;
202                 procctl();
203         }
204
205         scallnr = ureg->r0;
206         up->scallnr = scallnr;
207         spllo();
208
209         sp = ureg->sp;
210         up->nerrlab = 0;
211         ret = -1;
212         if(!waserror()){
213                 if(scallnr >= nsyscall){
214                         pprint("bad sys call number %d pc %#lux\n",
215                                 scallnr, ureg->pc);
216                         postnote(up, 1, "sys: bad sys call", NDebug);
217                         error(Ebadarg);
218                 }
219
220                 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
221                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
222
223                 up->s = *((Sargs*)(sp+BY2WD));
224                 up->psstate = sysctab[scallnr];
225
226         /*      iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
227
228                 ret = systab[scallnr]((va_list)up->s.args);
229                 poperror();
230         }else{
231                 /* failure: save the error buffer for errstr */
232                 e = up->syserrstr;
233                 up->syserrstr = up->errstr;
234                 up->errstr = e;
235         }
236         if(up->nerrlab){
237                 print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
238                 for(i = 0; i < NERR; i++)
239                         print("sp=%#p pc=%#p\n",
240                                 up->errlab[i].sp, up->errlab[i].pc);
241                 panic("error stack");
242         }
243
244         /*
245          *  Put return value in frame.  On the x86 the syscall is
246          *  just another trap and the return value from syscall is
247          *  ignored.  On other machines the return value is put into
248          *  the results register by caller of syscall.
249          */
250         ureg->r0 = ret;
251
252         if(up->procctl == Proc_tracesyscall){
253                 s = splhi();
254                 up->procctl = Proc_stopme;
255                 procctl();
256                 splx(s);
257         }
258
259         up->insyscall = 0;
260         up->psstate = 0;
261
262         if(scallnr == NOTED)
263                 noted(ureg, *(ulong*)(sp+BY2WD));
264
265         splhi();
266         if(scallnr != RFORK && (up->procctl || up->nnote))
267                 notify(ureg);
268
269         /* if we delayed sched because we held a lock, sched now */
270         if(up->delaysched){
271                 sched();
272                 splhi();
273         }
274         kexit(ureg);
275 }
276
277
278 uintptr
279 execregs(uintptr entry, ulong ssize, ulong nargs)
280 {
281         ulong *sp;
282         Ureg *ureg;
283
284         sp = (ulong*)(USTKTOP - ssize);
285         *--sp = nargs;
286
287         ureg = up->dbgreg;
288 //      memset(ureg, 0, 15*sizeof(ulong));
289         ureg->r13 = (ulong)sp;
290         ureg->pc = entry;
291 //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
292
293         /*
294          * return the address of kernel/user shared data
295          * (e.g. clock stuff)
296          */
297         return USTKTOP-sizeof(Tos);
298 }
299
300 void
301 sysprocsetup(Proc* p)
302 {
303         fpusysprocsetup(p);
304 }
305
306 /* 
307  *  Craft a return frame which will cause the child to pop out of
308  *  the scheduler in user mode with the return register zero.  Set
309  *  pc to point to a l.s return function.
310  */
311 void
312 forkchild(Proc *p, Ureg *ureg)
313 {
314         Ureg *cureg;
315
316 //print("%lud setting up for forking child %lud\n", up->pid, p->pid);
317         p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
318         p->sched.pc = (ulong)forkret;
319
320         cureg = (Ureg*)(p->sched.sp);
321         memmove(cureg, ureg, sizeof(Ureg));
322
323         /* syscall returns 0 for child */
324         cureg->r0 = 0;
325
326         /* Things from bottom of syscall which were never executed */
327         p->psstate = 0;
328         p->insyscall = 0;
329 }