The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/trap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "tos.h"
    3 #include        "../port/lib.h"
    4 #include        "mem.h"
    5 #include        "dat.h"
    6 #include        "fns.h"
    7 #include        "io.h"
    8 #include        "ureg.h"
    9 #include        "../port/error.h"
   10 #include        <trace.h>
   11 
   12 static int trapinited;
   13 
   14 void    noted(Ureg*, ulong);
   15 
   16 static void debugbpt(Ureg*, void*);
   17 static void fault386(Ureg*, void*);
   18 static void doublefault(Ureg*, void*);
   19 static void unexpected(Ureg*, void*);
   20 static void _dumpstack(Ureg*);
   21 
   22 static Lock vctllock;
   23 static Vctl *vctl[256];
   24 
   25 enum
   26 {
   27         Ntimevec = 20           /* number of time buckets for each intr */
   28 };
   29 ulong intrtimes[256][Ntimevec];
   30 
   31 void
   32 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
   33 {
   34         int vno;
   35         Vctl *v;
   36 
   37         if(f == nil){
   38                 print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
   39                         irq, tbdf, name);
   40                 return;
   41         }
   42 
   43         v = xalloc(sizeof(Vctl));
   44         v->isintr = 1;
   45         v->irq = irq;
   46         v->tbdf = tbdf;
   47         v->f = f;
   48         v->a = a;
   49         strncpy(v->name, name, KNAMELEN-1);
   50         v->name[KNAMELEN-1] = 0;
   51 
   52         ilock(&vctllock);
   53         vno = arch->intrenable(v);
   54         if(vno == -1){
   55                 iunlock(&vctllock);
   56                 print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
   57                         irq, tbdf, v->name);
   58                 xfree(v);
   59                 return;
   60         }
   61         if(vctl[vno]){
   62                 if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
   63                         panic("intrenable: handler: %s %s %#p %#p %#p %#p",
   64                                 vctl[vno]->name, v->name,
   65                                 vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
   66                 v->next = vctl[vno];
   67         }
   68         vctl[vno] = v;
   69         iunlock(&vctllock);
   70 }
   71 
   72 int
   73 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
   74 {
   75         Vctl **pv, *v;
   76         int vno;
   77 
   78         /*
   79          * For now, none of this will work with the APIC code,
   80          * there is no mapping between irq and vector as the IRQ
   81          * is pretty meaningless.
   82          */
   83         if(arch->intrvecno == nil)
   84                 return -1;
   85         vno = arch->intrvecno(irq);
   86         ilock(&vctllock);
   87         pv = &vctl[vno];
   88         while (*pv && 
   89                   ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
   90                    strcmp((*pv)->name, name)))
   91                 pv = &((*pv)->next);
   92         assert(*pv);
   93 
   94         v = *pv;
   95         *pv = (*pv)->next;      /* Link out the entry */
   96         
   97         if(vctl[vno] == nil && arch->intrdisable != nil)
   98                 arch->intrdisable(irq);
   99         iunlock(&vctllock);
  100         xfree(v);
  101         return 0;
  102 }
  103 
  104 static long
  105 irqallocread(Chan*, void *vbuf, long n, vlong offset)
  106 {
  107         char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
  108         int m, vno;
  109         long oldn;
  110         Vctl *v;
  111 
  112         if(n < 0 || offset < 0)
  113                 error(Ebadarg);
  114 
  115         oldn = n;
  116         buf = vbuf;
  117         for(vno=0; vno<nelem(vctl); vno++){
  118                 for(v=vctl[vno]; v; v=v->next){
  119                         m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
  120                         if(m <= offset) /* if do not want this, skip entry */
  121                                 offset -= m;
  122                         else{
  123                                 /* skip offset bytes */
  124                                 m -= offset;
  125                                 p = str+offset;
  126                                 offset = 0;
  127 
  128                                 /* write at most max(n,m) bytes */
  129                                 if(m > n)
  130                                         m = n;
  131                                 memmove(buf, p, m);
  132                                 n -= m;
  133                                 buf += m;
  134 
  135                                 if(n == 0)
  136                                         return oldn;
  137                         }       
  138                 }
  139         }
  140         return oldn - n;
  141 }
  142 
  143 void
  144 trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
  145 {
  146         Vctl *v;
  147 
  148         if(vno < 0 || vno >= VectorPIC)
  149                 panic("trapenable: vno %d", vno);
  150         v = xalloc(sizeof(Vctl));
  151         v->tbdf = BUSUNKNOWN;
  152         v->f = f;
  153         v->a = a;
  154         strncpy(v->name, name, KNAMELEN);
  155         v->name[KNAMELEN-1] = 0;
  156 
  157         ilock(&vctllock);
  158         if(vctl[vno])
  159                 v->next = vctl[vno]->next;
  160         vctl[vno] = v;
  161         iunlock(&vctllock);
  162 }
  163 
  164 static void
  165 nmienable(void)
  166 {
  167         int x;
  168 
  169         /*
  170          * Hack: should be locked with NVRAM access.
  171          */
  172         outb(0x70, 0x80);               /* NMI latch clear */
  173         outb(0x70, 0);
  174 
  175         x = inb(0x61) & 0x07;           /* Enable NMI */
  176         outb(0x61, 0x08|x);
  177         outb(0x61, x);
  178 }
  179 
  180 /*
  181  * Minimal trap setup.  Just enough so that we can panic
  182  * on traps (bugs) during kernel initialization.  
  183  * Called very early - malloc is not yet available.
  184  */
  185 void
  186 trapinit0(void)
  187 {
  188         int d1, v;
  189         ulong vaddr;
  190         Segdesc *idt;
  191 
  192         idt = (Segdesc*)IDTADDR;
  193         vaddr = (ulong)vectortable;
  194         for(v = 0; v < 256; v++){
  195                 d1 = (vaddr & 0xFFFF0000)|SEGP;
  196                 switch(v){
  197 
  198                 case VectorBPT:
  199                         d1 |= SEGPL(3)|SEGIG;
  200                         break;
  201 
  202                 case VectorSYSCALL:
  203                         d1 |= SEGPL(3)|SEGIG;
  204                         break;
  205 
  206                 default:
  207                         d1 |= SEGPL(0)|SEGIG;
  208                         break;
  209                 }
  210                 idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
  211                 idt[v].d1 = d1;
  212                 vaddr += 6;
  213         }
  214 }
  215 
  216 void
  217 trapinit(void)
  218 {
  219         /*
  220          * Special traps.
  221          * Syscall() is called directly without going through trap().
  222          */
  223         trapenable(VectorBPT, debugbpt, 0, "debugpt");
  224         trapenable(VectorPF, fault386, 0, "fault386");
  225         trapenable(Vector2F, doublefault, 0, "doublefault");
  226         trapenable(Vector15, unexpected, 0, "unexpected");
  227         nmienable();
  228 
  229         addarchfile("irqalloc", 0444, irqallocread, nil);
  230         trapinited = 1;
  231 }
  232 
  233 static char* excname[32] = {
  234         "divide error",
  235         "debug exception",
  236         "nonmaskable interrupt",
  237         "breakpoint",
  238         "overflow",
  239         "bounds check",
  240         "invalid opcode",
  241         "coprocessor not available",
  242         "double fault",
  243         "coprocessor segment overrun",
  244         "invalid TSS",
  245         "segment not present",
  246         "stack exception",
  247         "general protection violation",
  248         "page fault",
  249         "15 (reserved)",
  250         "coprocessor error",
  251         "alignment check",
  252         "machine check",
  253         "19 (reserved)",
  254         "20 (reserved)",
  255         "21 (reserved)",
  256         "22 (reserved)",
  257         "23 (reserved)",
  258         "24 (reserved)",
  259         "25 (reserved)",
  260         "26 (reserved)",
  261         "27 (reserved)",
  262         "28 (reserved)",
  263         "29 (reserved)",
  264         "30 (reserved)",
  265         "31 (reserved)",
  266 };
  267 
  268 /*
  269  *  keep histogram of interrupt service times
  270  */
  271 void
  272 intrtime(Mach*, int vno)
  273 {
  274         ulong diff;
  275         ulong x;
  276 
  277         x = perfticks();
  278         diff = x - m->perf.intrts;
  279         m->perf.intrts = x;
  280 
  281         m->perf.inintr += diff;
  282         if(up == nil && m->perf.inidle > diff)
  283                 m->perf.inidle -= diff;
  284 
  285         diff /= m->cpumhz*100;          /* quantum = 100µsec */
  286         if(diff >= Ntimevec)
  287                 diff = Ntimevec-1;
  288         intrtimes[vno][diff]++;
  289 }
  290 
  291 /* go to user space */
  292 void
  293 kexit(Ureg*)
  294 {
  295         uvlong t;
  296         Tos *tos;
  297 
  298         /* precise time accounting, kernel exit */
  299         tos = (Tos*)(USTKTOP-sizeof(Tos));
  300         cycles(&t);
  301         tos->kcycles += t - up->kentry;
  302         tos->pcycles = up->pcycles;
  303         tos->pid = up->pid;
  304 }
  305 
  306 /*
  307  *  All traps come here.  It is slower to have all traps call trap()
  308  *  rather than directly vectoring the handler.  However, this avoids a
  309  *  lot of code duplication and possible bugs.  The only exception is
  310  *  VectorSYSCALL.
  311  *  Trap is called with interrupts disabled via interrupt-gates.
  312  */
  313 void
  314 trap(Ureg* ureg)
  315 {
  316         int clockintr, i, vno, user;
  317         char buf[ERRMAX];
  318         Vctl *ctl, *v;
  319         Mach *mach;
  320 
  321         if(!trapinited){
  322                 /* fault386 can give a better error message */
  323                 if(ureg->trap == VectorPF)
  324                         fault386(ureg, nil);
  325                 panic("trap %lud: not ready", ureg->trap);
  326         }
  327 
  328         m->perf.intrts = perfticks();
  329         user = (ureg->cs & 0xFFFF) == UESEL;
  330         if(user){
  331                 up->dbgreg = ureg;
  332                 cycles(&up->kentry);
  333         }
  334 
  335         clockintr = 0;
  336 
  337         vno = ureg->trap;
  338         if(ctl = vctl[vno]){
  339                 if(ctl->isintr){
  340                         m->intr++;
  341                         if(vno >= VectorPIC && vno != VectorSYSCALL)
  342                                 m->lastintr = ctl->irq;
  343                 }
  344 
  345                 if(ctl->isr)
  346                         ctl->isr(vno);
  347                 for(v = ctl; v != nil; v = v->next){
  348                         if(v->f)
  349                                 v->f(ureg, v->a);
  350                 }
  351                 if(ctl->eoi)
  352                         ctl->eoi(vno);
  353 
  354                 if(ctl->isintr){
  355                         intrtime(m, vno);
  356 
  357                         if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
  358                                 clockintr = 1;
  359 
  360                         if(up && !clockintr)
  361                                 preempted();
  362                 }
  363         }
  364         else if(vno < nelem(excname) && user){
  365                 spllo();
  366                 sprint(buf, "sys: trap: %s", excname[vno]);
  367                 postnote(up, 1, buf, NDebug);
  368         }
  369         else if(vno >= VectorPIC && vno != VectorSYSCALL){
  370                 /*
  371                  * An unknown interrupt.
  372                  * Check for a default IRQ7. This can happen when
  373                  * the IRQ input goes away before the acknowledge.
  374                  * In this case, a 'default IRQ7' is generated, but
  375                  * the corresponding bit in the ISR isn't set.
  376                  * In fact, just ignore all such interrupts.
  377                  */
  378 
  379                 /* call all interrupt routines, just in case */
  380                 for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
  381                         ctl = vctl[i];
  382                         if(ctl == nil)
  383                                 continue;
  384                         if(!ctl->isintr)
  385                                 continue;
  386                         for(v = ctl; v != nil; v = v->next){
  387                                 if(v->f)
  388                                         v->f(ureg, v->a);
  389                         }
  390                         /* should we do this? */
  391                         if(ctl->eoi)
  392                                 ctl->eoi(i);
  393                 }
  394 
  395                 /* clear the interrupt */
  396                 i8259isr(vno);
  397 
  398                 if(0)print("cpu%d: spurious interrupt %d, last %d\n",
  399                         m->machno, vno, m->lastintr);
  400                 if(0)if(conf.nmach > 1){
  401                         for(i = 0; i < 32; i++){
  402                                 if(!(active.machs & (1<<i)))
  403                                         continue;
  404                                 mach = MACHP(i);
  405                                 if(m->machno == mach->machno)
  406                                         continue;
  407                                 print(" cpu%d: last %d",
  408                                         mach->machno, mach->lastintr);
  409                         }
  410                         print("\n");
  411                 }
  412                 m->spuriousintr++;
  413                 if(user)
  414                         kexit(ureg);
  415                 return;
  416         }
  417         else{
  418                 if(vno == VectorNMI){
  419                         /*
  420                          * Don't re-enable, it confuses the crash dumps.
  421                         nmienable();
  422                          */
  423                         iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc);
  424                         while(m->machno != 0)
  425                                 ;
  426                 }
  427                 dumpregs(ureg);
  428                 if(!user){
  429                         ureg->sp = (ulong)&ureg->sp;
  430                         _dumpstack(ureg);
  431                 }
  432                 if(vno < nelem(excname))
  433                         panic("%s", excname[vno]);
  434                 panic("unknown trap/intr: %d", vno);
  435         }
  436         splhi();
  437 
  438         /* delaysched set because we held a lock or because our quantum ended */
  439         if(up && up->delaysched && clockintr){
  440                 sched();
  441                 splhi();
  442         }
  443 
  444         if(user){
  445                 if(up->procctl || up->nnote)
  446                         notify(ureg);
  447                 kexit(ureg);
  448         }
  449 }
  450 
  451 /*
  452  *  dump registers
  453  */
  454 void
  455 dumpregs2(Ureg* ureg)
  456 {
  457         if(up)
  458                 iprint("cpu%d: registers for %s %lud\n",
  459                         m->machno, up->text, up->pid);
  460         else
  461                 iprint("cpu%d: registers for kernel\n", m->machno);
  462         iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
  463                 ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
  464         iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
  465         iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
  466                 ureg->ax, ureg->bx, ureg->cx, ureg->dx);
  467         iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
  468                 ureg->si, ureg->di, ureg->bp);
  469         iprint("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
  470                 ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
  471                 ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
  472 }
  473 
  474 void
  475 dumpregs(Ureg* ureg)
  476 {
  477         vlong mca, mct;
  478 
  479         dumpregs2(ureg);
  480 
  481         /*
  482          * Processor control registers.
  483          * If machine check exception, time stamp counter, page size extensions
  484          * or enhanced virtual 8086 mode extensions are supported, there is a
  485          * CR4. If there is a CR4 and machine check extensions, read the machine
  486          * check address and machine check type registers if RDMSR supported.
  487          */
  488         iprint("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
  489                 getcr0(), getcr2(), getcr3());
  490         if(m->cpuiddx & 0x9A){
  491                 iprint(" CR4 %8.8lux", getcr4());
  492                 if((m->cpuiddx & 0xA0) == 0xA0){
  493                         rdmsr(0x00, &mca);
  494                         rdmsr(0x01, &mct);
  495                         iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
  496                 }
  497         }
  498         iprint("\n  ur %#p up %#p\n", ureg, up);
  499 }
  500 
  501 
  502 /*
  503  * Fill in enough of Ureg to get a stack trace, and call a function.
  504  * Used by debugging interface rdb.
  505  */
  506 void
  507 callwithureg(void (*fn)(Ureg*))
  508 {
  509         Ureg ureg;
  510         ureg.pc = getcallerpc(&fn);
  511         ureg.sp = (ulong)&fn;
  512         fn(&ureg);
  513 }
  514 
  515 static void
  516 _dumpstack(Ureg *ureg)
  517 {
  518         uintptr l, v, i, estack;
  519         extern ulong etext;
  520         int x;
  521         char *s;
  522 
  523         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "") != 0){
  524                 iprint("dumpstack disabled\n");
  525                 return;
  526         }
  527         iprint("dumpstack\n");
  528 
  529         x = 0;
  530         x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
  531         i = 0;
  532         if(up
  533         && (uintptr)&l >= (uintptr)up->kstack
  534         && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
  535                 estack = (uintptr)up->kstack+KSTACK;
  536         else if((uintptr)&l >= (uintptr)m->stack
  537         && (uintptr)&l <= (uintptr)m+MACHSIZE)
  538                 estack = (uintptr)m+MACHSIZE;
  539         else
  540                 return;
  541         x += iprint("estackx %p\n", estack);
  542 
  543         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
  544                 v = *(uintptr*)l;
  545                 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
  546                         /*
  547                          * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
  548                          * and CALL indirect through AX
  549                          * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
  550                          * but this is too clever and misses faulting address.
  551                          */
  552                         x += iprint("%.8p=%.8p ", l, v);
  553                         i++;
  554                 }
  555                 if(i == 4){
  556                         i = 0;
  557                         x += iprint("\n");
  558                 }
  559         }
  560         if(i)
  561                 iprint("\n");
  562         iprint("EOF\n");
  563 
  564         if(ureg->trap != VectorNMI)
  565                 return;
  566 
  567         i = 0;
  568         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
  569                 iprint("%.8p ", *(uintptr*)l);
  570                 if(++i == 8){
  571                         i = 0;
  572                         iprint("\n");
  573                 }
  574         }
  575         if(i)
  576                 iprint("\n");
  577 }
  578 
  579 void
  580 dumpstack(void)
  581 {
  582         callwithureg(_dumpstack);
  583 }
  584 
  585 static void
  586 debugbpt(Ureg* ureg, void*)
  587 {
  588         char buf[ERRMAX];
  589 
  590         if(up == 0)
  591                 panic("kernel bpt");
  592         /* restore pc to instruction that caused the trap */
  593         ureg->pc--;
  594         sprint(buf, "sys: breakpoint");
  595         postnote(up, 1, buf, NDebug);
  596 }
  597 
  598 static void
  599 doublefault(Ureg*, void*)
  600 {
  601         panic("double fault");
  602 }
  603 
  604 static void
  605 unexpected(Ureg* ureg, void*)
  606 {
  607         print("unexpected trap %lud; ignoring\n", ureg->trap);
  608 }
  609 
  610 extern void checkpages(void);
  611 extern void checkfault(ulong, ulong);
  612 static void
  613 fault386(Ureg* ureg, void*)
  614 {
  615         ulong addr;
  616         int read, user, n, insyscall;
  617         char buf[ERRMAX];
  618 
  619         addr = getcr2();
  620         read = !(ureg->ecode & 2);
  621 
  622         user = (ureg->cs & 0xFFFF) == UESEL;
  623         if(!user){
  624                 if(vmapsync(addr))
  625                         return;
  626                 if(addr >= USTKTOP)
  627                         panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
  628                 if(up == nil)
  629                         panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
  630         }
  631         if(up == nil)
  632                 panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
  633 
  634         insyscall = up->insyscall;
  635         up->insyscall = 1;
  636         n = fault(addr, read);
  637         if(n < 0){
  638                 if(!user){
  639                         dumpregs(ureg);
  640                         panic("fault: 0x%lux", addr);
  641                 }
  642                 checkpages();
  643                 checkfault(addr, ureg->pc);
  644                 sprint(buf, "sys: trap: fault %s addr=0x%lux",
  645                         read ? "read" : "write", addr);
  646                 postnote(up, 1, buf, NDebug);
  647         }
  648         up->insyscall = insyscall;
  649 }
  650 
  651 /*
  652  *  system calls
  653  */
  654 #include "../port/systab.h"
  655 
  656 /*
  657  *  Syscall is called directly from assembler without going through trap().
  658  */
  659 void
  660 syscall(Ureg* ureg)
  661 {
  662         char *e;
  663         ulong   sp;
  664         long    ret;
  665         int     i, s;
  666         ulong scallnr;
  667 
  668         if((ureg->cs & 0xFFFF) != UESEL)
  669                 panic("syscall: cs 0x%4.4luX", ureg->cs);
  670 
  671         cycles(&up->kentry);
  672 
  673         m->syscall++;
  674         up->insyscall = 1;
  675         up->pc = ureg->pc;
  676         up->dbgreg = ureg;
  677 
  678         if(up->procctl == Proc_tracesyscall){
  679                 up->procctl = Proc_stopme;
  680                 procctl(up);
  681         }
  682 
  683         scallnr = ureg->ax;
  684         up->scallnr = scallnr;
  685         if(scallnr == RFORK && up->fpstate == FPactive){
  686                 fpsave(&up->fpsave);
  687                 up->fpstate = FPinactive;
  688         }
  689         spllo();
  690 
  691         sp = ureg->usp;
  692         up->nerrlab = 0;
  693         ret = -1;
  694         if(!waserror()){
  695                 if(scallnr >= nsyscall || systab[scallnr] == 0){
  696                         pprint("bad sys call number %d pc %lux\n",
  697                                 scallnr, ureg->pc);
  698                         postnote(up, 1, "sys: bad sys call", NDebug);
  699                         error(Ebadarg);
  700                 }
  701 
  702                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
  703                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
  704 
  705                 up->s = *((Sargs*)(sp+BY2WD));
  706                 up->psstate = sysctab[scallnr];
  707 
  708                 ret = systab[scallnr](up->s.args);
  709                 poperror();
  710         }else{
  711                 /* failure: save the error buffer for errstr */
  712                 e = up->syserrstr;
  713                 up->syserrstr = up->errstr;
  714                 up->errstr = e;
  715                 if(0 && up->pid == 1)
  716                         print("syscall %lud error %s\n", scallnr, up->syserrstr);
  717         }
  718         if(up->nerrlab){
  719                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
  720                 for(i = 0; i < NERR; i++)
  721                         print("sp=%lux pc=%lux\n",
  722                                 up->errlab[i].sp, up->errlab[i].pc);
  723                 panic("error stack");
  724         }
  725 
  726         /*
  727          *  Put return value in frame.  On the x86 the syscall is
  728          *  just another trap and the return value from syscall is
  729          *  ignored.  On other machines the return value is put into
  730          *  the results register by caller of syscall.
  731          */
  732         ureg->ax = ret;
  733 
  734         if(up->procctl == Proc_tracesyscall){
  735                 up->procctl = Proc_stopme;
  736                 s = splhi();
  737                 procctl(up);
  738                 splx(s);
  739         }
  740 
  741         up->insyscall = 0;
  742         up->psstate = 0;
  743 
  744         if(scallnr == NOTED)
  745                 noted(ureg, *(ulong*)(sp+BY2WD));
  746 
  747         if(scallnr!=RFORK && (up->procctl || up->nnote)){
  748                 splhi();
  749                 notify(ureg);
  750         }
  751         /* if we delayed sched because we held a lock, sched now */
  752         if(up->delaysched)
  753                 sched();
  754         kexit(ureg);
  755 }
  756 
  757 /*
  758  *  Call user, if necessary, with note.
  759  *  Pass user the Ureg struct and the note on his stack.
  760  */
  761 int
  762 notify(Ureg* ureg)
  763 {
  764         int l;
  765         ulong s, sp;
  766         Note *n;
  767 
  768         if(up->procctl)
  769                 procctl(up);
  770         if(up->nnote == 0)
  771                 return 0;
  772 
  773         if(up->fpstate == FPactive){
  774                 fpsave(&up->fpsave);
  775                 up->fpstate = FPinactive;
  776         }
  777         up->fpstate |= FPillegal;
  778 
  779         s = spllo();
  780         qlock(&up->debug);
  781         up->notepending = 0;
  782         n = &up->note[0];
  783         if(strncmp(n->msg, "sys:", 4) == 0){
  784                 l = strlen(n->msg);
  785                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
  786                         l = ERRMAX-15;
  787                 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
  788         }
  789 
  790         if(n->flag!=NUser && (up->notified || up->notify==0)){
  791                 if(n->flag == NDebug)
  792                         pprint("suicide: %s\n", n->msg);
  793                 qunlock(&up->debug);
  794                 pexit(n->msg, n->flag!=NDebug);
  795         }
  796 
  797         if(up->notified){
  798                 qunlock(&up->debug);
  799                 splhi();
  800                 return 0;
  801         }
  802 
  803         if(!up->notify){
  804                 qunlock(&up->debug);
  805                 pexit(n->msg, n->flag!=NDebug);
  806         }
  807         sp = ureg->usp;
  808         sp -= 256;      /* debugging: preserve context causing problem */
  809         sp -= sizeof(Ureg);
  810 if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n", 
  811         up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
  812 
  813         if(!okaddr((ulong)up->notify, 1, 0)
  814         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
  815                 pprint("suicide: bad address in notify\n");
  816                 qunlock(&up->debug);
  817                 pexit("Suicide", 0);
  818         }
  819 
  820         memmove((Ureg*)sp, ureg, sizeof(Ureg));
  821         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
  822         up->ureg = (void*)sp;
  823         sp -= BY2WD+ERRMAX;
  824         memmove((char*)sp, up->note[0].msg, ERRMAX);
  825         sp -= 3*BY2WD;
  826         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;             /* arg 2 is string */
  827         *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;        /* arg 1 is ureg* */
  828         *(ulong*)(sp+0*BY2WD) = 0;                      /* arg 0 is pc */
  829         ureg->usp = sp;
  830         ureg->pc = (ulong)up->notify;
  831         up->notified = 1;
  832         up->nnote--;
  833         memmove(&up->lastnote, &up->note[0], sizeof(Note));
  834         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
  835 
  836         qunlock(&up->debug);
  837         splx(s);
  838         return 1;
  839 }
  840 
  841 /*
  842  *   Return user to state before notify()
  843  */
  844 void
  845 noted(Ureg* ureg, ulong arg0)
  846 {
  847         Ureg *nureg;
  848         ulong oureg, sp;
  849 
  850         qlock(&up->debug);
  851         if(arg0!=NRSTR && !up->notified) {
  852                 qunlock(&up->debug);
  853                 pprint("call to noted() when not notified\n");
  854                 pexit("Suicide", 0);
  855         }
  856         up->notified = 0;
  857 
  858         nureg = up->ureg;       /* pointer to user returned Ureg struct */
  859 
  860         up->fpstate &= ~FPillegal;
  861 
  862         /* sanity clause */
  863         oureg = (ulong)nureg;
  864         if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
  865                 pprint("bad ureg in noted or call to noted when not notified\n");
  866                 qunlock(&up->debug);
  867                 pexit("Suicide", 0);
  868         }
  869 
  870         /*
  871          * Check the segment selectors are all valid, otherwise
  872          * a fault will be taken on attempting to return to the
  873          * user process.
  874          * Take care with the comparisons as different processor
  875          * generations push segment descriptors in different ways.
  876          */
  877         if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
  878           || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
  879           || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
  880                 pprint("bad segment selector in noted\n");
  881                 qunlock(&up->debug);
  882                 pexit("Suicide", 0);
  883         }
  884 
  885         /* don't let user change system flags */
  886         nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
  887 
  888         memmove(ureg, nureg, sizeof(Ureg));
  889 
  890         switch(arg0){
  891         case NCONT:
  892         case NRSTR:
  893 if(0) print("%s %lud: noted %.8lux %.8lux\n", 
  894         up->text, up->pid, nureg->pc, nureg->usp);
  895                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
  896                         qunlock(&up->debug);
  897                         pprint("suicide: trap in noted\n");
  898                         pexit("Suicide", 0);
  899                 }
  900                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
  901                 qunlock(&up->debug);
  902                 break;
  903 
  904         case NSAVE:
  905                 if(!okaddr(nureg->pc, BY2WD, 0)
  906                 || !okaddr(nureg->usp, BY2WD, 0)){
  907                         qunlock(&up->debug);
  908                         pprint("suicide: trap in noted\n");
  909                         pexit("Suicide", 0);
  910                 }
  911                 qunlock(&up->debug);
  912                 sp = oureg-4*BY2WD-ERRMAX;
  913                 splhi();
  914                 ureg->sp = sp;
  915                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
  916                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
  917                 break;
  918 
  919         default:
  920                 pprint("unknown noted arg 0x%lux\n", arg0);
  921                 up->lastnote.flag = NDebug;
  922                 /* fall through */
  923                 
  924         case NDFLT:
  925                 if(up->lastnote.flag == NDebug){ 
  926                         qunlock(&up->debug);
  927                         pprint("suicide: %s\n", up->lastnote.msg);
  928                 } else
  929                         qunlock(&up->debug);
  930                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
  931         }
  932 }
  933 
  934 long
  935 execregs(ulong entry, ulong ssize, ulong nargs)
  936 {
  937         ulong *sp;
  938         Ureg *ureg;
  939 
  940         up->fpstate = FPinit;
  941         fpoff();
  942 
  943         sp = (ulong*)(USTKTOP - ssize);
  944         *--sp = nargs;
  945 
  946         ureg = up->dbgreg;
  947         ureg->usp = (ulong)sp;
  948         ureg->pc = entry;
  949         return USTKTOP-sizeof(Tos);             /* address of kernel/user shared data */
  950 }
  951 
  952 /*
  953  *  return the userpc the last exception happened at
  954  */
  955 ulong
  956 userpc(void)
  957 {
  958         Ureg *ureg;
  959 
  960         ureg = (Ureg*)up->dbgreg;
  961         return ureg->pc;
  962 }
  963 
  964 /* This routine must save the values of registers the user is not permitted
  965  * to write from devproc and then restore the saved values before returning.
  966  */
  967 void
  968 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
  969 {
  970         ulong cs, ds, es, flags, fs, gs, ss;
  971 
  972         ss = ureg->ss;
  973         flags = ureg->flags;
  974         cs = ureg->cs;
  975         ds = ureg->ds;
  976         es = ureg->es;
  977         fs = ureg->fs;
  978         gs = ureg->gs;
  979         memmove(pureg, uva, n);
  980         ureg->gs = gs;
  981         ureg->fs = fs;
  982         ureg->es = es;
  983         ureg->ds = ds;
  984         ureg->cs = cs;
  985         ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
  986         ureg->ss = ss;
  987 }
  988 
  989 static void
  990 linkproc(void)
  991 {
  992         spllo();
  993         up->kpfun(up->kparg);
  994         pexit("kproc dying", 0);
  995 }
  996 
  997 void
  998 kprocchild(Proc* p, void (*func)(void*), void* arg)
  999 {
 1000         /*
 1001          * gotolabel() needs a word on the stack in
 1002          * which to place the return PC used to jump
 1003          * to linkproc().
 1004          */
 1005         p->sched.pc = (ulong)linkproc;
 1006         p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
 1007 
 1008         p->kpfun = func;
 1009         p->kparg = arg;
 1010 }
 1011 
 1012 void
 1013 forkchild(Proc *p, Ureg *ureg)
 1014 {
 1015         Ureg *cureg;
 1016 
 1017         /*
 1018          * Add 2*BY2WD to the stack to account for
 1019          *  - the return PC
 1020          *  - trap's argument (ur)
 1021          */
 1022         p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
 1023         p->sched.pc = (ulong)forkret;
 1024 
 1025         cureg = (Ureg*)(p->sched.sp+2*BY2WD);
 1026         memmove(cureg, ureg, sizeof(Ureg));
 1027         /* return value of syscall in child */
 1028         cureg->ax = 0;
 1029 
 1030         /* Things from bottom of syscall which were never executed */
 1031         p->psstate = 0;
 1032         p->insyscall = 0;
 1033 }
 1034 
 1035 /* Give enough context in the ureg to produce a kernel stack for
 1036  * a sleeping process
 1037  */
 1038 void
 1039 setkernur(Ureg* ureg, Proc* p)
 1040 {
 1041         ureg->pc = p->sched.pc;
 1042         ureg->sp = p->sched.sp+4;
 1043 }
 1044 
 1045 ulong
 1046 dbgpc(Proc *p)
 1047 {
 1048         Ureg *ureg;
 1049 
 1050         ureg = p->dbgreg;
 1051         if(ureg == 0)
 1052                 return 0;
 1053 
 1054         return ureg->pc;
 1055 }

Cache object: 246c741afeb85acce3a812d6273a150e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.