trap.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       trap.c (22655B)
       ---
            1 /*
            2  * Heavily modified copy of /sys/src/9/pc/trap.c
            3  * A shell of its former self.
            4  */
            5 #define        WANT_M
            6 
            7 #include        "u.h"
            8 #include        "libvx32/vx32.h"
            9 #include        "tos.h"
           10 #include        "lib.h"
           11 #include        "mem.h"
           12 #include        "dat.h"
           13 #include        "fns.h"
           14 #include        "io.h"
           15 #include        "ureg.h"
           16 #include        "error.h"
           17 #include        "trace.h"
           18 #include        "systab.h"
           19 
           20 int tracesyscalls;
           21 static void noted(Ureg*, ulong);
           22 static void mathemu(Ureg*, void*);
           23 static void syscall(Ureg*);
           24 
           25 /* going to user space */
           26 void
           27 kexit(Ureg *ureg)
           28 {
           29         uvlong t;
           30         Tos *tos;
           31 
           32         /* precise time accounting, kernel exit */
           33         tos = (Tos*)(up->pmmu.uzero+USTKTOP-sizeof(Tos));
           34         cycles(&t);
           35         tos->kcycles += t - up->kentry;
           36         tos->pcycles = up->pcycles;
           37         tos->pid = up->pid;
           38 }
           39 
           40 static char* excname[32] = {
           41         "divide error",
           42         "debug exception",
           43         "nonmaskable interrupt",
           44         "breakpoint",
           45         "overflow",
           46         "bounds check",
           47         "invalid opcode",
           48         "coprocessor not available",
           49         "double fault",
           50         "coprocessor segment overrun",
           51         "invalid TSS",
           52         "segment not present",
           53         "stack exception",
           54         "general protection violation",
           55         "page fault",
           56         "15 (reserved)",
           57         "coprocessor error",
           58         "alignment check",
           59         "machine check",
           60         "19 (reserved)",
           61         "20 (reserved)",
           62         "21 (reserved)",
           63         "22 (reserved)",
           64         "23 (reserved)",
           65         "24 (reserved)",
           66         "25 (reserved)",
           67         "26 (reserved)",
           68         "27 (reserved)",
           69         "28 (reserved)",
           70         "29 (reserved)",
           71         "30 (reserved)",
           72         "31 (reserved)",
           73 };
           74 
           75 /*
           76  * Handle a trap.
           77  */
           78 void
           79 trap(Ureg *ureg)
           80 {
           81         char buf[ERRMAX];
           82         int vno;
           83 
           84         vno = ureg->trap;
           85 
           86         switch(vno){
           87         case VXTRAP_FPOFF:
           88                 mathemu(ureg, nil);
           89                 return;
           90         
           91         case VXTRAP_SOFT+0x40:        /* int $0x40 - system call */
           92                 if(tracesyscalls){
           93                         uint32 *sp = (uint32*)(up->pmmu.uzero + ureg->usp);
           94                         iprint("%d [%s] %s %#ux %08ux %08ux %08ux %08ux\n",
           95                                 up->pid, up->text,
           96                                 sysctab[ureg->ax], sp[0], sp[1], sp[2], sp[3]);
           97                 }
           98                 syscall(ureg);
           99                 if(tracesyscalls){
          100                         if(ureg->ax == -1)
          101                                 iprint("%d [%s] -> %s\n", up->pid, up->text, up->syserrstr);
          102                         else
          103                                 iprint("%d [%s] -> %#ux\n", up->pid, up->text, ureg->ax);
          104                 }
          105                 return;
          106         
          107         case VXTRAP_IRQ+VXIRQ_TIMER:
          108                 sched();
          109                 break;
          110         
          111         case 3:        // breakpoint
          112                 /* restore pc to instruction that caused the trap */
          113                 ureg->pc--;
          114                 sprint(buf, "sys: breakpoint");
          115                 postnote(up, 1, buf, NDebug);
          116                 break;
          117 
          118         default:
          119                 if(vno < nelem(excname)){
          120                         spllo();
          121                         sprint(buf, "sys: trap: %s", excname[vno]);
          122                         postnote(up, 1, buf, NDebug);
          123                 }else{
          124                         dumpregs(ureg);
          125                         if(vno < nelem(excname))
          126                                 panic("%s", excname[vno]);
          127                         panic("unknown trap/intr: %#x", vno);
          128                 }
          129                 break;
          130         }
          131 
          132         if(up->procctl || up->nnote)
          133                 notify(ureg);
          134         spllo();        /* no actual effect, just silences prints */
          135         kexit(ureg);
          136 }
          137 
          138 void
          139 dumpregs2(Ureg* ureg)
          140 {
          141         if(up)
          142                 print("cpu%d: registers for %s %lud\n",
          143                         m->machno, up->text, up->pid);
          144         else
          145                 print("cpu%d: registers for kernel\n", m->machno);
          146         print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
          147                 ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
          148         print(" USP=%luX\n", ureg->usp);
          149         print("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
          150                 ureg->ax, ureg->bx, ureg->cx, ureg->dx);
          151         print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
          152                 ureg->si, ureg->di, ureg->bp);
          153 }
          154 
          155 void
          156 dumpregs(Ureg* ureg)
          157 {
          158         dumpregs2(ureg);
          159 
          160         /*
          161          * Processor control registers.
          162          * If machine check exception, time stamp counter, page size extensions
          163          * or enhanced virtual 8086 mode extensions are supported, there is a
          164          * CR4. If there is a CR4 and machine check extensions, read the machine
          165          * check address and machine check type registers if RDMSR supported.
          166         print("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
          167                 getcr0(), getcr2(), getcr3());
          168         if(m->cpuiddx & 0x9A){
          169                 vlong mca, mct;
          170                 iprint(" CR4 %8.8lux", getcr4());
          171                 if((m->cpuiddx & 0xA0) == 0xA0){
          172                         rdmsr(0x00, &mca);
          173                         rdmsr(0x01, &mct);
          174                         iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
          175                 }
          176         }
          177         print("\n  ur %lux up %lux\n", ureg, up);
          178          */
          179 }
          180 
          181 static void
          182 fmtrwdata(Fmt *f, ulong s, int n, char *suffix)
          183 {
          184         char *t, *src;
          185         int i;
          186 
          187         if (! s) {
          188                 fmtprint(f, "0x0", suffix);
          189                 return;
          190         }
          191         src = uvalidaddr(s, 1, 0);
          192         t = smalloc(n+1);
          193         for(i = 0; i < n; i++)
          194                 if (isgraph(src[i]))
          195                         t[i] = src[i];
          196                 else
          197                         t[i] = '.';
          198 
          199         fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
          200         free(t);
          201 }
          202 
          203 static void
          204 fmtuserstring(Fmt *f, ulong s, char *suffix)
          205 {
          206         char *es, *t, *src;
          207         int n;
          208 
          209         if (! s){
          210                 fmtprint(f, "0/\"\"%s", suffix);
          211                 return;
          212         }
          213         src = uvalidaddr(s, 1, 0);
          214         es = vmemchr(src, 0, 1<<16);
          215         n = es - src;
          216         t = smalloc(n+1);
          217         memmove(t, src, n);
          218         t[n] = 0;
          219         fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
          220         free(t);
          221 }
          222 
          223 static void
          224 syscallprint(Ureg *ureg)
          225 {
          226         uint32 *sp;
          227         int syscallno;
          228         vlong offset;
          229         Fmt fmt;
          230         int len;
          231           uint32 argp, a;
          232 
          233         sp = (uint32*)(up->pmmu.uzero + ureg->usp);
          234         syscallno = ureg->ax;
          235         offset = 0;
          236         fmtstrinit(&fmt);
          237         fmtprint(&fmt, "%d %s ", up->pid, up->text);
          238         /* accomodate process-private system calls */
          239 
          240         if(syscallno > nelem(sysctab))
          241                 fmtprint(&fmt, " %d %#x ", syscallno, sp[0]);
          242         else
          243                 fmtprint(&fmt, "%s %#ux ", sysctab[syscallno], sp[0]);
          244 
          245         if(up->syscalltrace)
          246                 free(up->syscalltrace);
          247 
          248         switch(syscallno) {
          249         case SYSR1:
          250                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          251                 break;
          252         case _ERRSTR:
          253                 fmtuserstring(&fmt, sp[1], "");
          254                 break;
          255         case BIND:
          256                 fmtuserstring(&fmt, sp[1], " ");
          257                 fmtuserstring(&fmt, sp[2], " ");
          258                 fmtprint(&fmt, "%#ux",  sp[3]);
          259                 break;
          260         case CHDIR:
          261                 fmtuserstring(&fmt, sp[1], "");
          262                 break;
          263         case CLOSE:
          264                 fmtprint(&fmt, "%d", sp[1]);
          265                 break;
          266         case DUP:
          267                 fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
          268                 break;
          269         case ALARM:
          270                 fmtprint(&fmt, "%08ux ", sp[1]);
          271                 break;
          272         case EXEC: 
          273                 fmtuserstring(&fmt, sp[1], "");
          274                 argp = sp[2];
          275                 for(;;argp += BY2WD) {
          276                         a = *(uint32*)uvalidaddr(argp, BY2WD, 0);
          277                         if(a == 0)
          278                                 break;
          279                         fmtprint(&fmt, " ");
          280                         fmtuserstring(&fmt, a, "");
          281                 }
          282                 break;
          283         case EXITS:
          284                 fmtuserstring(&fmt, sp[1], "");
          285                 break;
          286         case _FSESSION:
          287                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          288                 break;
          289         case FAUTH:
          290                 fmtprint(&fmt, "%08ux", sp[1]);
          291                 fmtuserstring(&fmt, sp[2], "");
          292                 break;
          293         case _FSTAT:
          294                 fmtprint(&fmt, "%08ux %#ux %08ux", sp[1], sp[2], sp[3]);
          295                 break;
          296         case SEGBRK:
          297                 fmtprint(&fmt, "%#ux %#ux", sp[1], sp[2]);
          298                 break;
          299         case _MOUNT:
          300                 fmtprint(&fmt, "%d %d ", sp[1], sp[2]);
          301                 fmtuserstring(&fmt, sp[3], " ");
          302                 fmtprint(&fmt, "%08ux ", sp[4]);
          303                 fmtuserstring(&fmt, sp[5], "");
          304                 break;
          305         case OPEN:
          306                 fmtuserstring(&fmt, sp[1], " ");
          307                 fmtprint(&fmt, "%08ux", sp[2]);
          308                 break;
          309         case OSEEK:
          310                 fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
          311                 break;
          312         case SLEEP: 
          313                 fmtprint(&fmt, "%d", sp[1]);
          314                 break;
          315         case _STAT:
          316                 fmtuserstring(&fmt, sp[1], " ");
          317                 fmtprint(&fmt, "%#ux %d", sp[2], sp[3]);
          318                 break;
          319         case RFORK:
          320                 fmtprint(&fmt, "%08ux", sp[1] );
          321                 break;
          322         case PIPE: 
          323                 break;
          324         case CREATE:
          325                 fmtuserstring(&fmt, sp[1], " ");
          326                 fmtprint(&fmt, "%08ux %08ux", sp[2], sp[3]);
          327                 break;
          328         case FD2PATH:
          329                 fmtprint(&fmt, "%d ", sp[1]);
          330                 break;
          331         case BRK_:
          332                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          333                 break;
          334         case REMOVE:
          335                 fmtuserstring(&fmt, sp[1], " ");
          336                 break;
          337         /* deprecated */
          338         case _WSTAT:
          339                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          340                 break;
          341         case _FWSTAT:
          342                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          343                 break;
          344         case NOTIFY:
          345                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          346                 break;
          347         case NOTED:
          348                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          349                 break;
          350         case SEGATTACH:
          351                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          352                 break;
          353         case SEGDETACH:
          354                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          355                 break;
          356         case SEGFREE:
          357                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          358                 break;
          359         case SEGFLUSH:
          360                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          361                 break;
          362         case RENDEZVOUS:
          363                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          364                 break;
          365         case UNMOUNT:
          366                 fmtuserstring(&fmt, sp[1], " ");
          367                 break;
          368         case _WAIT:
          369                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          370                 break;
          371         case SEMACQUIRE:
          372                 fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
          373                 break;
          374         case SEMRELEASE:
          375                 fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
          376                 break;
          377         case SEEK:
          378                 fmtprint(&fmt, "%08ux %016ux %08ux", sp[1], *(vlong *)&sp[2], sp[4]);
          379                 break;
          380         case FVERSION:
          381                 fmtprint(&fmt, "%08ux %08ux ", sp[1], sp[2]);
          382                 fmtuserstring(&fmt, sp[5], "");
          383                 break;
          384         case ERRSTR:
          385                 fmtprint(&fmt, "%#ux/", sp[1]);
          386                 break;
          387         case WSTAT:
          388         case STAT:
          389                 fmtprint(&fmt, "%08ux ", sp[1]);
          390                 fmtuserstring(&fmt, sp[2], " ");
          391                 fmtprint(&fmt, "%08ux", sp[3]);
          392                 break;
          393         case FSTAT:
          394         case FWSTAT:
          395                 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
          396                 break;
          397         case MOUNT:
          398                 fmtprint(&fmt, "%d %d ", sp[1], sp[3]);
          399                 fmtuserstring(&fmt, sp[3], " ");
          400                 fmtprint(&fmt, "%08ux", sp[4]);
          401                 fmtuserstring(&fmt, sp[5], "");
          402                 break;
          403         case AWAIT:
          404                 break;
          405         case _READ: 
          406         case PREAD:
          407                 fmtprint(&fmt, "%d ", sp[1]);
          408                 break;
          409         case _WRITE:
          410                 offset = -1;
          411         case PWRITE:
          412                 fmtprint(&fmt, "%d ", sp[1]);
          413                 if (sp[3] < 64)
          414                         len = sp[3];
          415                 else
          416                         len = 64;
          417                 fmtrwdata(&fmt, sp[2], len, " ");
          418                 if(! offset)
          419                         offset = *(vlong *)&sp[4];
          420                 fmtprint(&fmt, "%d %#llx", sp[3], offset);
          421                 break;
          422         }
          423         up->syscalltrace = fmtstrflush(&fmt);
          424 }
          425 
          426 static void
          427 retprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop)
          428 {
          429         int errstrlen, len;
          430         vlong offset;
          431         char *errstr;
          432         Fmt fmt;
          433 
          434         fmtstrinit(&fmt);
          435         len = 0;
          436         errstrlen = 0;
          437         offset = 0;
          438         if (ureg->ax != -1)
          439                 errstr = "";
          440         else
          441                 errstr = up->syserrstr;
          442 
          443         if(up->syscalltrace)
          444                 free(up->syscalltrace);
          445 
          446         switch(syscallno) {
          447         case SYSR1:
          448         case BIND:
          449         case CHDIR:
          450         case CLOSE:
          451         case DUP:
          452         case ALARM:
          453         case EXEC:
          454         case EXITS:
          455         case _FSESSION:
          456         case FAUTH:
          457         case _FSTAT:
          458         case SEGBRK:
          459         case _MOUNT:
          460         case OPEN:
          461         case OSEEK:
          462         case SLEEP:
          463         case _STAT:
          464         case _WRITE:
          465         case PIPE:
          466         case CREATE:
          467         case BRK_:
          468         case REMOVE:
          469         case _WSTAT:
          470         case _FWSTAT:
          471         case NOTIFY:
          472         case NOTED:
          473         case SEGATTACH:
          474         case SEGDETACH:
          475         case SEGFREE:
          476         case SEGFLUSH:
          477         case RENDEZVOUS:
          478         case UNMOUNT:
          479         case _WAIT:
          480         case SEMACQUIRE:
          481         case SEMRELEASE:
          482         case SEEK:
          483         case FVERSION:
          484         case STAT:
          485         case FSTAT:
          486         case WSTAT:
          487         case FWSTAT:
          488         case MOUNT:
          489         case PWRITE:
          490         case RFORK:
          491         default: 
          492         break;
          493         case AWAIT:
          494                 if(ureg->ax > 0){
          495                         fmtuserstring(&fmt, up->s.args[0], " ");
          496                         fmtprint(&fmt, "%d", up->s.args[1]);
          497                 } else {
          498                         fmtprint(&fmt, "%#ux/\"\" %d", up->s.args[0], up->s.args[1]);
          499                 }
          500                 break;
          501         case _ERRSTR:
          502                 errstrlen = 64;
          503         case ERRSTR:
          504                 if(! errstrlen)
          505                         errstrlen = up->s.args[1];
          506                 if(ureg->ax > 0){
          507                         fmtuserstring(&fmt, up->s.args[0], " ");
          508                         fmtprint(&fmt, "%d", errstrlen);
          509                 } else {
          510                         fmtprint(&fmt, "\"\" %d", errstrlen);
          511                 }
          512                 break;
          513         case FD2PATH:
          514                 if(ureg->ax == -1)
          515                         fmtprint(&fmt, "\"\" %d", up->s.args[2]);
          516                 else {
          517                         fmtuserstring(&fmt, up->s.args[1], " ");
          518                         fmtprint(&fmt, "%d", errstrlen);
          519                 }
          520                 break;
          521         case _READ:
          522                 offset = -1;
          523         case PREAD:
          524                 if(ureg->ax == -1)
          525                         fmtprint(&fmt, "/\"\" %d 0x%ullx", up->s.args[2], *(vlong *)&up->s.args[3]);
          526                 else {
          527                         if (ureg->ax > 64)
          528                                 len = 64;
          529                         else
          530                                 len = ureg->ax;
          531                         fmtrwdata(&fmt, up->s.args[1], len, " ");
          532                         if(! offset)
          533                                 offset = *(vlong *)&up->s.args[3];
          534                         fmtprint(&fmt, "%d %#llx", up->s.args[2], offset);
          535                 }
          536         break;
          537         }
          538 
          539         if (syscallno == EXEC) 
          540                 fmtprint(&fmt, " = %p \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
          541         else
          542                 fmtprint(&fmt, " = %d \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
          543 
          544         up->syscalltrace = fmtstrflush(&fmt);
          545 }
          546 /*
          547  * Handle a system call.
          548  */
          549 static void
          550 syscall(Ureg *ureg)
          551 {
          552         char *e;
          553         ulong sp;
          554         uchar *usp;
          555         long        ret;
          556         int s;
          557         ulong scallnr;
          558         vlong startnsec, stopnsec;
          559 
          560         USED(startnsec);
          561         cycles(&up->kentry);
          562         m->syscall++;
          563         up->insyscall = 1;
          564         up->pc = ureg->pc;
          565         up->dbgreg = ureg;
          566 
          567         if(up->procctl == Proc_tracesyscall){
          568                 up->procctl = Proc_stopme;
          569                 syscallprint(ureg);
          570                 procctl(up);
          571                 if(up->syscalltrace)
          572                         free(up->syscalltrace);
          573                 up->syscalltrace = nil;
          574                 startnsec = todget(nil);
          575         }
          576 
          577         scallnr = ureg->ax;
          578         up->scallnr = scallnr;
          579         if(scallnr == RFORK && up->fpstate == FPactive){
          580                 fpsave(&up->fpsave);
          581                 up->fpstate = FPinactive;
          582         }
          583         spllo();
          584 
          585         sp = ureg->usp;
          586         up->nerrlab = 0;
          587         ret = -1;
          588         if(!waserror()){
          589                 if(scallnr >= nsyscall || systab[scallnr] == 0){
          590                         pprint("bad sys call number %d pc %lux\n",
          591                                 scallnr, ureg->pc);
          592                         postnote(up, 1, "sys: bad sys call", NDebug);
          593                         error(Ebadarg);
          594                 }
          595 
          596                 
          597                 usp = uvalidaddr(sp, sizeof(Sargs)+BY2WD, 0);
          598                 up->s = *((Sargs*)(usp+BY2WD));
          599                 up->psstate = sysctab[scallnr];
          600 
          601                 ret = systab[scallnr](up->s.args);
          602                 poperror();
          603         }else{
          604                 /* failure: save the error buffer for errstr */
          605                 e = up->syserrstr;
          606                 up->syserrstr = up->errstr;
          607                 up->errstr = e;
          608                 if(0 && up->pid == 1)
          609                         print("syscall %lud error %s\n", scallnr, up->syserrstr);
          610         }
          611         if(up->nerrlab){
          612                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
          613         //        for(i = 0; i < NERR; i++)
          614         //                print("sp=%lux pc=%lux\n",
          615         //XXX                        up->errlab[i].sp, up->errlab[i].pc);
          616                 panic("error stack");
          617         }
          618 
          619 //        if(ret < 0)
          620 //                print("%d [%s] %s\n", up->pid, up->psstate, up->syserrstr);
          621 //        else
          622 //                print("%d [%s] %d\n", up->pid, up->psstate, ret);
          623 //        printmap();
          624 
          625         /*
          626          *  Put return value in frame.  On the x86 the syscall is
          627          *  just another trap and the return value from syscall is
          628          *  ignored.  On other machines the return value is put into
          629          *  the results register by caller of syscall.
          630          */
          631         ureg->ax = ret;
          632 
          633         if(up->procctl == Proc_tracesyscall){
          634                 stopnsec = todget(nil);
          635                 up->procctl = Proc_stopme;
          636                 retprint(ureg, scallnr, startnsec, stopnsec);
          637                 s = splhi();
          638                 procctl(up);
          639                 splx(s);
          640                 if(up->syscalltrace)
          641                         free(up->syscalltrace);
          642                 up->syscalltrace = nil;
          643         }
          644 
          645         up->insyscall = 0;
          646         up->psstate = 0;
          647 
          648         if(scallnr == NOTED)
          649                 noted(ureg, *(uint32*)(up->pmmu.uzero + sp+BY2WD));
          650 
          651         if(scallnr!=RFORK && (up->procctl || up->nnote)){
          652                 splhi();
          653                 notify(ureg);
          654         }
          655         /* if we delayed sched because we held a lock, sched now */
          656         if(up->delaysched)
          657                 sched();
          658         kexit(ureg);
          659 }
          660 
          661 /*
          662  *  Call user, if necessary, with note.
          663  *  Pass user the Ureg struct and the note on his stack.
          664  */
          665 int
          666 notify(Ureg* ureg)
          667 {
          668         int l;
          669         ulong s, sp;
          670         Note *n;
          671         Ureg *upureg;
          672 
          673         if(tracesyscalls)
          674                 iprint("notify\n");
          675 
          676         if(up->procctl)
          677                 procctl(up);
          678         if(up->nnote == 0)
          679                 return 0;
          680 
          681         if(up->fpstate == FPactive){
          682                 fpsave(&up->fpsave);
          683                 up->fpstate = FPinactive;
          684         }
          685         up->fpstate |= FPillegal;
          686 
          687         s = spllo();
          688         qlock(&up->debug);
          689         up->notepending = 0;
          690         n = &up->note[0];
          691         if(strncmp(n->msg, "sys:", 4) == 0){
          692                 l = strlen(n->msg);
          693                 if(l > ERRMAX-15)        /* " pc=0x12345678\0" */
          694                         l = ERRMAX-15;
          695                 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
          696         }
          697 
          698         if(n->flag!=NUser && (up->notified || up->notify==0)){
          699                 if(n->flag == NDebug)
          700                         pprint("suicide: %s\n", n->msg);
          701                 qunlock(&up->debug);
          702                 pexit(n->msg, n->flag!=NDebug);
          703         }
          704 
          705         if(up->notified){
          706                 qunlock(&up->debug);
          707                 splhi();
          708                 return 0;
          709         }
          710                 
          711         if(!up->notify){
          712                 qunlock(&up->debug);
          713                 pexit(n->msg, n->flag!=NDebug);
          714         }
          715         sp = ureg->usp;
          716         sp -= sizeof(Ureg);
          717 
          718         if(!okaddr(up->notify, 1, 0)
          719         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
          720                 pprint("suicide: bad address in notify\n");
          721                 qunlock(&up->debug);
          722                 pexit("Suicide", 0);
          723         }
          724 
          725         uchar *uzero;
          726         uzero = up->pmmu.uzero;
          727         upureg = (void*)(uzero + sp);
          728         memmove(upureg, ureg, sizeof(Ureg));
          729         *(uint32*)(uzero + sp-BY2WD) = up->ureg;        /* word under Ureg is old up->ureg */
          730         up->ureg = sp;
          731         sp -= BY2WD+ERRMAX;
          732         memmove((char*)(uzero + sp), up->note[0].msg, ERRMAX);
          733         sp -= 3*BY2WD;
          734         *(uint32*)(uzero + sp+2*BY2WD) = sp+3*BY2WD;                /* arg 2 is string */
          735         *(uint32*)(uzero + sp+1*BY2WD) = up->ureg;        /* arg 1 is ureg* */
          736         *(uint32*)(uzero + sp+0*BY2WD) = 0;                        /* arg 0 is pc */
          737         ureg->usp = sp;
          738         ureg->pc = up->notify;
          739         up->notified = 1;
          740         up->nnote--;
          741         memmove(&up->lastnote, &up->note[0], sizeof(Note));
          742         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
          743 
          744         qunlock(&up->debug);
          745         splx(s);
          746         return 1;
          747 }
          748 
          749 /*
          750  *   Return user to state before notify()
          751  */
          752 static void
          753 noted(Ureg* ureg, ulong arg0)
          754 {
          755         Ureg *nureg;
          756         ulong oureg, sp;
          757 
          758         qlock(&up->debug);
          759         if(arg0!=NRSTR && !up->notified) {
          760                 qunlock(&up->debug);
          761                 pprint("call to noted() when not notified\n");
          762                 pexit("Suicide", 0);
          763         }
          764         up->notified = 0;
          765 
          766         up->fpstate &= ~FPillegal;
          767 
          768         /* sanity clause */
          769         if(!okaddr(up->ureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
          770                 pprint("bad ureg in noted or call to noted when not notified\n");
          771                 qunlock(&up->debug);
          772                 pexit("Suicide", 0);
          773         }
          774         
          775         uchar *uzero;
          776         uzero = up->pmmu.uzero;
          777         oureg = up->ureg;
          778         nureg = (Ureg*)(uzero + up->ureg);
          779 
          780         /* don't let user change system flags */
          781         nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
          782 
          783         memmove(ureg, nureg, sizeof(Ureg));
          784 
          785         switch(arg0){
          786         case NCONT:
          787         case NRSTR:
          788                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
          789                         qunlock(&up->debug);
          790                         pprint("suicide: trap in noted\n");
          791                         pexit("Suicide", 0);
          792                 }
          793                 up->ureg = *(uint32*)(uzero+oureg-BY2WD);
          794                 qunlock(&up->debug);
          795                 break;
          796 
          797         case NSAVE:
          798                 if(!okaddr(nureg->pc, BY2WD, 0)
          799                 || !okaddr(nureg->usp, BY2WD, 0)){
          800                         qunlock(&up->debug);
          801                         pprint("suicide: trap in noted\n");
          802                         pexit("Suicide", 0);
          803                 }
          804                 qunlock(&up->debug);
          805                 sp = oureg-4*BY2WD-ERRMAX;
          806                 splhi();
          807                 ureg->sp = sp;
          808                 ((uint32*)(uzero+sp))[1] = oureg;        /* arg 1 0(FP) is ureg* */
          809                 ((uint32*)(uzero+sp))[0] = 0;                /* arg 0 is pc */
          810                 break;
          811 
          812         default:
          813                 pprint("unknown noted arg 0x%lux\n", arg0);
          814                 up->lastnote.flag = NDebug;
          815                 /* fall through */
          816                 
          817         case NDFLT:
          818                 if(up->lastnote.flag == NDebug){ 
          819                         qunlock(&up->debug);
          820                         pprint("suicide: %s\n", up->lastnote.msg);
          821                 } else
          822                         qunlock(&up->debug);
          823                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
          824         }
          825 }
          826 
          827 long
          828 execregs(ulong entry, ulong ssize, ulong nargs)
          829 {
          830         uint32 *sp;
          831         Ureg *ureg;
          832 
          833         up->fpstate = FPinit;
          834         fpoff();
          835 
          836         sp = (uint32*)(up->pmmu.uzero + USTKTOP - ssize);
          837         *--sp = nargs;
          838 
          839         ureg = up->dbgreg;
          840         ureg->usp = (uchar*)sp - up->pmmu.uzero;
          841 //showexec(ureg->usp);
          842         ureg->pc = entry;
          843         return USTKTOP-sizeof(Tos);                /* address of kernel/user shared data */
          844 }
          845 
          846 /*
          847  *  return the userpc the last exception happened at
          848  */
          849 ulong
          850 userpc(void)
          851 {
          852         Ureg *ureg;
          853 
          854         ureg = (Ureg*)up->dbgreg;
          855         return ureg->pc;
          856 }
          857 
          858 /* This routine must save the values of registers the user is not permitted
          859  * to write from devproc and then restore the saved values before returning.
          860  */
          861 void
          862 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
          863 {
          864         ulong flags;
          865 
          866         flags = ureg->flags;
          867         memmove(pureg, uva, n);
          868         ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
          869 }
          870 
          871 static void
          872 linkproc(void)
          873 {
          874         spllo();
          875         up->kpfun(up->kparg);
          876         pexit("kproc dying", 0);
          877 }
          878 
          879 void
          880 kprocchild(Proc* p, void (*func)(void*), void* arg)
          881 {
          882         /*
          883          * gotolabel() needs a word on the stack in
          884          * which to place the return PC used to jump
          885          * to linkproc().
          886          */
          887         labelinit(&p->sched, (ulong)linkproc, (ulong)p->kstack+KSTACK-BY2WD);
          888 
          889         p->kpfun = func;
          890         p->kparg = arg;
          891 }
          892 
          893 void
          894 forkchild(Proc *p, Ureg *ureg)
          895 {
          896         Ureg *cureg;
          897         void *sp;
          898 
          899         /*
          900          * Add 2*BY2WD to the stack to account for
          901          *  - the return PC
          902          *  - trap's argument (ur)
          903          */
          904         sp = (char*)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
          905         labelinit(&p->sched, (ulong)forkret, (ulong)sp);
          906 
          907         cureg = (Ureg*)((char*)sp+2*BY2WD);
          908         memmove(cureg, ureg, sizeof(Ureg));
          909         /* return value of syscall in child */
          910         cureg->ax = 0;
          911 
          912         /* Things from bottom of syscall which were never executed */
          913         p->psstate = 0;
          914         p->insyscall = 0;
          915 }
          916 
          917 /*
          918  * Give enough context in the ureg to produce a kernel stack for
          919  * a sleeping process.  Or not.
          920  */
          921 void
          922 setkernur(Ureg* ureg, Proc* p)
          923 {
          924         memset(ureg, 0, sizeof *ureg);
          925 }
          926 
          927 ulong
          928 dbgpc(Proc *p)
          929 {
          930         Ureg *ureg;
          931 
          932         ureg = p->dbgreg;
          933         if(ureg == 0)
          934                 return 0;
          935 
          936         return ureg->pc;
          937 }
          938 
          939 /*
          940  * floating point and all its glory.
          941  */
          942 
          943 static char* mathmsg[] =
          944 {
          945         nil,        /* handled below */
          946         "denormalized operand",
          947         "division by zero",
          948         "numeric overflow",
          949         "numeric underflow",
          950         "precision loss",
          951 };
          952 
          953 static void
          954 mathnote(void)
          955 {
          956         int i;
          957         ulong status;
          958         char *msg, note[ERRMAX];
          959 
          960         status = up->fpsave.status;
          961 
          962         /*
          963          * Some attention should probably be paid here to the
          964          * exception masks and error summary.
          965          */
          966         msg = "unknown exception";
          967         for(i = 1; i <= 5; i++){
          968                 if(!((1<<i) & status))
          969                         continue;
          970                 msg = mathmsg[i];
          971                 break;
          972         }
          973         if(status & 0x01){
          974                 if(status & 0x40){
          975                         if(status & 0x200)
          976                                 msg = "stack overflow";
          977                         else
          978                                 msg = "stack underflow";
          979                 }else
          980                         msg = "invalid operation";
          981         }
          982         sprint(note, "sys: fp: %s fppc=0x%lux status=0x%lux", msg, up->fpsave.pc, status);
          983         postnote(up, 1, note, NDebug);
          984 }
          985 
          986 
          987 /*
          988  *  math coprocessor emulation fault
          989  */
          990 static void
          991 mathemu(Ureg *ureg, void *v)
          992 {
          993         if(up->fpstate & FPillegal){
          994                 /* someone did floating point in a note handler */
          995                 postnote(up, 1, "sys: floating point in note handler", NDebug);
          996                 return;
          997         }
          998         switch(up->fpstate){
          999         case FPinit:
         1000                 fpinit();
         1001                 up->fpstate = FPactive;
         1002                 break;
         1003         case FPinactive:
         1004                 /*
         1005                  * Before restoring the state, check for any pending
         1006                  * exceptions, there's no way to restore the state without
         1007                  * generating an unmasked exception.
         1008                  * More attention should probably be paid here to the
         1009                  * exception masks and error summary.
         1010                  */
         1011                 if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
         1012                         mathnote();
         1013                         break;
         1014                 }
         1015                 fprestore(&up->fpsave);
         1016                 up->fpstate = FPactive;
         1017                 break;
         1018         case FPactive:
         1019                 panic("math emu pid %ld %s pc 0x%lux", 
         1020                         up->pid, up->text, ureg->pc);
         1021                 break;
         1022         }
         1023 }
         1024 
         1025 /*
         1026  *  math coprocessor segment overrun
         1027  * TODO: When to call this?
         1028  */
         1029 void
         1030 mathover(Ureg *u, void *v)
         1031 {
         1032         pexit("math overrun", 0);
         1033 }
         1034 
         1035 /*
         1036  *  math coprocessor error
         1037  * TODO: When to call this?
         1038  */
         1039 void
         1040 matherror(Ureg *ur, void *v)
         1041 {
         1042         /*
         1043          *  a write cycle to port 0xF0 clears the interrupt latch attached
         1044          *  to the error# line from the 387
         1045          */
         1046 //        if(!(m->cpuiddx & 0x01))
         1047 //                outb(0xF0, 0xFF);
         1048 
         1049         /*
         1050          *  save floating point state to check out error
         1051          */
         1052         fpenv(&up->fpsave);
         1053         mathnote();
         1054 
         1055         if(!okaddr(ur->pc, 1, 0))
         1056                 panic("fp: status %ux fppc=0x%lux pc=0x%lux",
         1057                         up->fpsave.status, up->fpsave.pc, ur->pc);
         1058 }
         1059 
         1060 /*
         1061  *  set up floating point for a new process
         1062  */
         1063 void
         1064 procsetup(Proc*p)
         1065 {
         1066         p->fpstate = FPinit;
         1067         fpoff();
         1068 }
         1069 
         1070 void
         1071 procrestore(Proc *p)
         1072 {
         1073         uvlong t;
         1074 
         1075         if(p->kp)
         1076                 return;
         1077         cycles(&t);
         1078         p->pcycles -= t;
         1079 }
         1080 
         1081 /*
         1082  *  Save the mach dependent part of the process state.
         1083  */
         1084 void
         1085 procsave(Proc *p)
         1086 {
         1087         uvlong t;
         1088 
         1089         cycles(&t);
         1090         p->pcycles += t;
         1091         if(p->fpstate == FPactive){
         1092                 if(p->state == Moribund)
         1093                         fpclear();
         1094                 else{
         1095                         /*
         1096                          * Fpsave() stores without handling pending
         1097                          * unmasked exeptions. Postnote() can't be called
         1098                          * here as sleep() already has up->rlock, so
         1099                          * the handling of pending exceptions is delayed
         1100                          * until the process runs again and generates an
         1101                          * emulation fault to activate the FPU.
         1102                          */
         1103                         fpsave(&p->fpsave);
         1104                 }
         1105                 p->fpstate = FPinactive;
         1106         }
         1107 }