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/powerpc/powerpc/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 /*
    2  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
    3  * Copyright (C) 1995, 1996 TooLs GmbH.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by TooLs GmbH.
   17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/5.2/sys/powerpc/powerpc/trap.c 114305 2003-04-30 17:59:27Z jhb $");
   36 
   37 #include "opt_ddb.h"
   38 #include "opt_ktrace.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/proc.h>
   42 #include <sys/ktr.h>
   43 #include <sys/lock.h>
   44 #include <sys/mutex.h>
   45 #include <sys/pioctl.h>
   46 #include <sys/reboot.h>
   47 #include <sys/syscall.h>
   48 #include <sys/sysent.h>
   49 #include <sys/systm.h>
   50 #include <sys/uio.h>
   51 #include <sys/user.h>
   52 #ifdef KTRACE
   53 #include <sys/ktrace.h>
   54 #endif
   55 #include <sys/vmmeter.h>
   56 
   57 #include <vm/vm.h>
   58 #include <vm/pmap.h>
   59 #include <vm/vm_extern.h>
   60 #include <vm/vm_param.h>
   61 #include <vm/vm_kern.h>
   62 #include <vm/vm_map.h>
   63 #include <vm/vm_page.h>
   64 
   65 #include <machine/cpu.h>
   66 #include <machine/db_machdep.h>
   67 #include <machine/fpu.h>
   68 #include <machine/frame.h>
   69 #include <machine/pcb.h>
   70 #include <machine/pmap.h>
   71 #include <machine/psl.h>
   72 #include <machine/trap.h>
   73 #include <machine/spr.h>
   74 #include <machine/sr.h>
   75 
   76 #include <ddb/ddb.h>
   77 
   78 #ifndef MULTIPROCESSOR
   79 extern int intr_depth;
   80 #endif
   81 
   82 void            trap(struct trapframe *);
   83 
   84 static void     trap_fatal(struct trapframe *frame);
   85 static void     printtrap(u_int vector, struct trapframe *frame, int isfatal,
   86                     int user);
   87 static int      trap_pfault(struct trapframe *frame, int user);
   88 static int      fix_unaligned(struct thread *td, struct trapframe *frame);
   89 static int      handle_onfault(struct trapframe *frame);
   90 static void     syscall(struct trapframe *frame);
   91 
   92 static __inline void    setusr(u_int);
   93 
   94 int     setfault(faultbuf);             /* defined in locore.S */
   95 
   96 /* Why are these not defined in a header? */
   97 int     badaddr(void *, size_t);
   98 int     badaddr_read(void *, size_t, int *);
   99 
  100 #ifdef  WITNESS
  101 extern char     *syscallnames[];
  102 #endif
  103 
  104 struct powerpc_exception {
  105         u_int   vector;
  106         char    *name;
  107 };
  108 
  109 static struct powerpc_exception powerpc_exceptions[] = {
  110         { 0x0100, "system reset" },
  111         { 0x0200, "machine check" },
  112         { 0x0300, "data storage interrupt" },
  113         { 0x0400, "instruction storage interrupt" },
  114         { 0x0500, "external interrupt" },
  115         { 0x0600, "alignment" },
  116         { 0x0700, "program" },
  117         { 0x0800, "floating-point unavailable" },
  118         { 0x0900, "decrementer" },
  119         { 0x0c00, "system call" },
  120         { 0x0d00, "trace" },
  121         { 0x0e00, "floating-point assist" },
  122         { 0x0f00, "performance monitoring" },
  123         { 0x0f20, "altivec unavailable" },
  124         { 0x1000, "instruction tlb miss" },
  125         { 0x1100, "data load tlb miss" },
  126         { 0x1200, "data store tlb miss" },
  127         { 0x1300, "instruction breakpoint" },
  128         { 0x1400, "system management" },                
  129         { 0x1600, "altivec assist" },
  130         { 0x1700, "thermal management" },
  131         { 0x2000, "run mode/trace" },
  132         { 0x3000, NULL }
  133 };
  134 
  135 static const char *
  136 trapname(u_int vector)
  137 {
  138         struct  powerpc_exception *pe;
  139 
  140         for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
  141                 if (pe->vector == vector)
  142                         return (pe->name);
  143         }
  144 
  145         return ("unknown");
  146 }
  147 
  148 void
  149 trap(struct trapframe *frame)
  150 {
  151         struct thread   *td;
  152         struct proc     *p;
  153         int             sig, type, user;
  154         u_int           sticks, ucode;
  155 
  156         atomic_add_int(&cnt.v_trap, 1);
  157 
  158         td = PCPU_GET(curthread);
  159         p = td->td_proc;
  160 
  161         type = ucode = frame->exc;
  162         sig = 0;
  163         user = frame->srr1 & PSL_PR;
  164         sticks = 0;
  165 
  166         CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
  167             trapname(type), user ? "user" : "kernel");
  168 
  169         if (user) {
  170                 sticks = td->td_sticks;
  171                 td->td_frame = frame;
  172                 if (td->td_ucred != p->p_ucred)
  173                         cred_update_thread(td);
  174 
  175                 /* User Mode Traps */
  176                 switch (type) {
  177                 case EXC_RUNMODETRC:
  178                 case EXC_TRC:
  179                         frame->srr1 &= ~PSL_SE;
  180                         sig = SIGTRAP;
  181                         break;
  182 
  183                 case EXC_DSI:
  184                 case EXC_ISI:
  185                         sig = trap_pfault(frame, 1);
  186                         break;
  187 
  188                 case EXC_SC:
  189                         syscall(frame);
  190                         break;
  191 
  192                 case EXC_FPU:
  193                         KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
  194                             ("FPU already enabled for thread"));
  195                         enable_fpu(td);
  196                         break;
  197 
  198 #ifdef  ALTIVEC
  199                 case EXC_VEC:
  200                         if ((vecthread = PCPU_GET(vecthread)) != NULL) {
  201                                 KASSERT(vecthread != td,
  202                                     ("altivec already enabled"));
  203                                 save_vec(vecthread);
  204                         }
  205                         PCPU_SET(vecthread, td);
  206                         td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
  207                         enable_vec(td);
  208                         frame->srr1 |= PSL_VEC;
  209                         break;
  210 #endif /* ALTIVEC */
  211 
  212                 case EXC_ALI:
  213                         if (fix_unaligned(td, frame) != 0)
  214                                 sig = SIGBUS;
  215                         else
  216                                 frame->srr0 += 4;
  217                         break;
  218 
  219                 case EXC_PGM:
  220                         /* XXX temporarily */
  221                         /* XXX: Magic Number? */
  222                         if (frame->srr1 & 0x0002000)
  223                                 sig = SIGTRAP;
  224                         else
  225                                 sig = SIGILL;
  226                         break;
  227 
  228                 default:
  229                         trap_fatal(frame);
  230                 }
  231         } else {
  232                 /* Kernel Mode Traps */
  233 
  234                 KASSERT(cold || td->td_ucred != NULL,
  235                     ("kernel trap doesn't have ucred"));
  236                 switch (type) {
  237                 case EXC_DSI:
  238                         if (trap_pfault(frame, 0) == 0)
  239                                 return;
  240                         break;
  241                 case EXC_MCHK:
  242                         if (handle_onfault(frame))
  243                                 return;
  244                         break;
  245                 default:
  246                         trap_fatal(frame);
  247                 }
  248         }
  249 
  250 #ifdef  ALTIVEC
  251         if (td != PCPU_GET(vecthread) ||
  252             td->td_pcb->pcb_veccpu != PCPU_GET(cpuid))
  253                 frame->srr1 &= ~PSL_VEC;
  254 #endif /* ALTIVEC */
  255 
  256         if (sig != 0) {
  257                 if (p->p_sysent->sv_transtrap != NULL)
  258                         sig = (p->p_sysent->sv_transtrap)(sig, type);
  259                 trapsignal(td, sig, ucode);
  260         }
  261 
  262         userret(td, frame, sticks);
  263         mtx_assert(&Giant, MA_NOTOWNED);
  264 #ifdef  DIAGNOSTIC
  265         cred_free_thread(td);
  266 #endif  /* DIAGNOSTIC */
  267 }
  268 
  269 static void
  270 trap_fatal(struct trapframe *frame)
  271 {
  272 
  273         printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
  274 #ifdef DDB
  275         if ((debugger_on_panic || db_active) && kdb_trap(frame->exc, frame))
  276                 return;
  277 #endif
  278         panic("%s trap", trapname(frame->exc));
  279 }
  280 
  281 static void
  282 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
  283 {
  284 
  285         printf("\n");
  286         printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
  287             user ? "user" : "kernel");
  288         printf("\n");
  289         printf("   exception       = 0x%x (%s)\n", vector >> 8,
  290             trapname(vector));
  291         switch (vector) {
  292         case EXC_DSI:
  293                 printf("   virtual address = 0x%x\n", frame->dar);
  294                 break;
  295         case EXC_ISI:
  296                 printf("   virtual address = 0x%x\n", frame->srr0);
  297                 break;
  298         }
  299         printf("   srr0            = 0x%x\n", frame->srr0);
  300         printf("   srr1            = 0x%x\n", frame->srr1);
  301         printf("   curthread       = %p\n", curthread);
  302         if (curthread != NULL)
  303                 printf("          pid = %d, comm = %s\n",
  304                     curthread->td_proc->p_pid, curthread->td_proc->p_comm);
  305         printf("\n");
  306 }
  307 
  308 /*
  309  * Handles a fatal fault when we have onfault state to recover.  Returns
  310  * non-zero if there was onfault recovery state available.
  311  */
  312 static int
  313 handle_onfault(struct trapframe *frame)
  314 {
  315         struct          thread *td;
  316         faultbuf        *fb;
  317 
  318         td = curthread;
  319         fb = td->td_pcb->pcb_onfault;
  320         if (fb != NULL) {
  321                 frame->srr0 = (*fb)[0];
  322                 frame->fixreg[1] = (*fb)[1];
  323                 frame->fixreg[2] = (*fb)[2];
  324                 frame->cr = (*fb)[3];
  325                 bcopy(&(*fb)[4], &frame->fixreg[13],
  326                     19 * sizeof(register_t));
  327                 return (1);
  328         }
  329         return (0);
  330 }
  331 
  332 void
  333 syscall(struct trapframe *frame)
  334 {
  335         caddr_t         params;
  336         struct          sysent *callp;
  337         struct          thread *td;
  338         struct          proc *p;
  339         int             error, n;
  340         size_t          narg;
  341         register_t      args[10];
  342         u_int           code;
  343 
  344         td = PCPU_GET(curthread);
  345         p = td->td_proc;
  346 
  347         atomic_add_int(&cnt.v_syscall, 1);
  348                         
  349         code = frame->fixreg[0];
  350         params = (caddr_t)(frame->fixreg + FIRSTARG);
  351         n = NARGREG;
  352                         
  353         if (p->p_sysent->sv_prepsyscall) {
  354                 /*
  355                  * The prep code is MP aware.
  356                  */
  357                 (*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
  358         } else if (code == SYS_syscall) {
  359                 /*
  360                  * code is first argument,
  361                  * followed by actual args.
  362                  */
  363                 code = *(u_int *) params;
  364                 params += sizeof(register_t);
  365                 n -= 1;
  366         } else if (code == SYS___syscall) {
  367                 /*
  368                  * Like syscall, but code is a quad,
  369                  * so as to maintain quad alignment
  370                  * for the rest of the args.
  371                  */
  372                 params += sizeof(register_t);
  373                 code = *(u_int *) params;
  374                 params += sizeof(register_t);
  375                 n -= 2;
  376         }
  377 
  378         if (p->p_sysent->sv_mask)
  379                 code &= p->p_sysent->sv_mask;
  380 
  381         if (code >= p->p_sysent->sv_size)
  382                 callp = &p->p_sysent->sv_table[0];
  383         else
  384                 callp = &p->p_sysent->sv_table[code];
  385 
  386         narg = callp->sy_narg & SYF_ARGMASK;
  387 
  388         if (narg > n) {
  389                 bcopy(params, args, n * sizeof(register_t));
  390                 error = copyin(MOREARGS(frame->fixreg[1]), args + n,
  391                                (narg - n) * sizeof(register_t));
  392                 params = (caddr_t)args;
  393         } else
  394                 error = 0;
  395 
  396 #ifdef  KTRACE
  397         if (KTRPOINT(td, KTR_SYSCALL))
  398                 ktrsyscall(code, narg, (register_t *)params);
  399 #endif
  400         /*
  401          * Try to run the syscall without Giant if the syscall is MP safe.
  402          */
  403         if ((callp->sy_narg & SYF_MPSAFE) == 0)
  404                 mtx_lock(&Giant);
  405 
  406         if (error == 0) {
  407                 td->td_retval[0] = 0;
  408                 td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
  409 
  410                 STOPEVENT(p, S_SCE, narg);
  411 
  412                 error = (*callp->sy_call)(td, params);
  413         }
  414         switch (error) {
  415         case 0:
  416                 if ((frame->fixreg[0] == SYS___syscall) && 
  417                     (code != SYS_lseek)) {
  418                         /*
  419                          * 64-bit return, 32-bit syscall. Fixup byte order
  420                          */
  421                         frame->fixreg[FIRSTARG] = 0;
  422                         frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
  423                 } else {
  424                         frame->fixreg[FIRSTARG] = td->td_retval[0];
  425                         frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
  426                 }
  427                 /* XXX: Magic number */
  428                 frame->cr &= ~0x10000000;
  429                 break;
  430         case ERESTART:
  431                 /*
  432                  * Set user's pc back to redo the system call.
  433                  */
  434                 frame->srr0 -= 4;
  435                 break;
  436         case EJUSTRETURN:
  437                 /* nothing to do */
  438                 break;
  439         default:
  440                 if (p->p_sysent->sv_errsize) {
  441                         if (error >= p->p_sysent->sv_errsize)
  442                                 error = -1;     /* XXX */
  443                         else
  444                                 error = p->p_sysent->sv_errtbl[error];
  445                 }
  446                 frame->fixreg[FIRSTARG] = error;
  447                 /* XXX: Magic number: Carry Flag Equivalent? */
  448                 frame->cr |= 0x10000000;
  449                 break;
  450         }
  451 
  452         
  453         if ((callp->sy_narg & SYF_MPSAFE) == 0)
  454                 mtx_unlock(&Giant);
  455 
  456 #ifdef  KTRACE
  457         if (KTRPOINT(td, KTR_SYSRET))
  458                 ktrsysret(code, error, td->td_retval[0]);
  459 #endif
  460 
  461         /*
  462          * Does the comment in the i386 code about errno apply here?
  463          */
  464         STOPEVENT(p, S_SCX, code);
  465 
  466         WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
  467             (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
  468         mtx_assert(&sched_lock, MA_NOTOWNED);
  469         mtx_assert(&Giant, MA_NOTOWNED);        
  470 }
  471 
  472 static int
  473 trap_pfault(struct trapframe *frame, int user)
  474 {
  475         vm_offset_t     eva, va;
  476         struct          thread *td;
  477         struct          proc *p;
  478         vm_map_t        map;
  479         vm_prot_t       ftype;
  480         int             rv;
  481         u_int           user_sr;
  482 
  483         td = curthread;
  484         p = td->td_proc;
  485         if (frame->exc == EXC_ISI) {
  486                 eva = frame->srr0;
  487                 ftype = VM_PROT_READ | VM_PROT_EXECUTE;
  488         } else {
  489                 eva = frame->dar;
  490                 if (frame->dsisr & DSISR_STORE)
  491                         ftype = VM_PROT_WRITE;
  492                 else
  493                         ftype = VM_PROT_READ;
  494         }
  495 
  496         if (user) {
  497                 map = &p->p_vmspace->vm_map;
  498         } else {
  499                 if ((eva >> ADDR_SR_SHFT) == USER_SR) {
  500                         if (p->p_vmspace == NULL)
  501                                 return (SIGSEGV);
  502                                 
  503                         __asm ("mfsr %0, %1"
  504                             : "=r"(user_sr)
  505                             : "K"(USER_SR));
  506                         eva &= ADDR_PIDX | ADDR_POFF;
  507                         eva |= user_sr << ADDR_SR_SHFT;
  508                         map = &p->p_vmspace->vm_map;
  509                 } else {
  510                         map = kernel_map;
  511                 }
  512         }
  513         va = trunc_page(eva);
  514 
  515         mtx_lock(&Giant);
  516         if (map != kernel_map) {
  517                 /*
  518                  * Keep swapout from messing with us during this
  519                  *      critical time.
  520                  */
  521                 PROC_LOCK(p);
  522                 ++p->p_lock;
  523                 PROC_UNLOCK(p);
  524 
  525                 /* Fault in the user page: */
  526                 rv = vm_fault(map, va, ftype,
  527                       (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
  528                                               : VM_FAULT_NORMAL);
  529 
  530                 PROC_LOCK(p);
  531                 --p->p_lock;
  532                 PROC_UNLOCK(p);
  533         } else {
  534                 /*
  535                  * Don't have to worry about process locking or stacks in the
  536                  * kernel.
  537                  */
  538                 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
  539         }
  540         mtx_unlock(&Giant);
  541 
  542         if (rv == KERN_SUCCESS)
  543                 return (0);
  544 
  545         if (!user && handle_onfault(frame))
  546                 return (0);
  547 
  548         return (SIGSEGV);
  549 }
  550 
  551 static __inline void
  552 setusr(u_int content)
  553 {
  554         __asm __volatile ("isync; mtsr %0,%1; isync"
  555                       :: "n"(USER_SR), "r"(content));
  556 }
  557 
  558 int
  559 badaddr(void *addr, size_t size)
  560 {
  561         return (badaddr_read(addr, size, NULL));
  562 }
  563 
  564 int
  565 badaddr_read(void *addr, size_t size, int *rptr)
  566 {
  567         struct thread   *td;
  568         faultbuf        env;
  569         int             x;
  570 
  571         /* Get rid of any stale machine checks that have been waiting.  */
  572         __asm __volatile ("sync; isync");
  573 
  574         td = PCPU_GET(curthread);
  575 
  576         if (setfault(env)) {
  577                 td->td_pcb->pcb_onfault = 0;
  578                 __asm __volatile ("sync");
  579                 return 1;
  580         }
  581 
  582         __asm __volatile ("sync");
  583 
  584         switch (size) {
  585         case 1:
  586                 x = *(volatile int8_t *)addr;
  587                 break;
  588         case 2:
  589                 x = *(volatile int16_t *)addr;
  590                 break;
  591         case 4:
  592                 x = *(volatile int32_t *)addr;
  593                 break;
  594         default:
  595                 panic("badaddr: invalid size (%d)", size);
  596         }
  597 
  598         /* Make sure we took the machine check, if we caused one. */
  599         __asm __volatile ("sync; isync");
  600 
  601         td->td_pcb->pcb_onfault = 0;
  602         __asm __volatile ("sync");      /* To be sure. */
  603 
  604         /* Use the value to avoid reorder. */
  605         if (rptr)
  606                 *rptr = x;
  607 
  608         return (0);
  609 }
  610 
  611 /*
  612  * For now, this only deals with the particular unaligned access case
  613  * that gcc tends to generate.  Eventually it should handle all of the
  614  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
  615  */
  616 
  617 static int
  618 fix_unaligned(struct thread *td, struct trapframe *frame)
  619 {
  620         struct thread   *fputhread;
  621         int             indicator, reg;
  622         double          *fpr;
  623 
  624         indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
  625 
  626         switch (indicator) {
  627         case EXC_ALI_LFD:
  628         case EXC_ALI_STFD:
  629                 reg = EXC_ALI_RST(frame->dsisr);
  630                 fpr = &td->td_pcb->pcb_fpu.fpr[reg];
  631                 fputhread = PCPU_GET(fputhread);
  632 
  633                 /* Juggle the FPU to ensure that we've initialized
  634                  * the FPRs, and that their current state is in
  635                  * the PCB.
  636                  */
  637                 if (fputhread != td) {
  638                         if (fputhread)
  639                                 save_fpu(fputhread);
  640                         enable_fpu(td);
  641                 }
  642                 save_fpu(td);
  643 
  644                 if (indicator == EXC_ALI_LFD) {
  645                         if (copyin((void *)frame->dar, fpr,
  646                             sizeof(double)) != 0)
  647                                 return -1;
  648                         enable_fpu(td);
  649                 } else {
  650                         if (copyout(fpr, (void *)frame->dar,
  651                             sizeof(double)) != 0)
  652                                 return -1;
  653                 }
  654                 return 0;
  655                 break;
  656         }
  657 
  658         return -1;
  659 }

Cache object: 7b6e76978cb18f203455a954ecb6034b


[ 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.