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/bsd/dev/ppc/systemcalls.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) 2000-2004 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * The contents of this file constitute Original Code as defined in and
    7  * are subject to the Apple Public Source License Version 1.1 (the
    8  * "License").  You may not use this file except in compliance with the
    9  * License.  Please obtain a copy of the License at
   10  * http://www.apple.com/publicsource and read it before using this file.
   11  * 
   12  * This Original Code and all software distributed under the License are
   13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
   17  * License for the specific language governing rights and limitations
   18  * under the License.
   19  * 
   20  * @APPLE_LICENSE_HEADER_END@
   21  */
   22 
   23 #include <kern/task.h>
   24 #include <kern/thread.h>
   25 #include <kern/assert.h>
   26 #include <kern/clock.h>
   27 #include <kern/locks.h>
   28 #include <kern/sched_prim.h>
   29 #include <mach/machine/thread_status.h>
   30 #include <ppc/savearea.h>
   31 
   32 #include <sys/kernel.h>
   33 #include <sys/vm.h>
   34 #include <sys/proc_internal.h>
   35 #include <sys/syscall.h>
   36 #include <sys/systm.h>
   37 #include <sys/user.h>
   38 #include <sys/errno.h>
   39 #include <sys/ktrace.h>
   40 #include <sys/kdebug.h>
   41 #include <sys/sysent.h>
   42 #include <sys/sysproto.h>
   43 #include <sys/kauth.h>
   44 
   45 #include <bsm/audit_kernel.h>
   46 
   47 extern void
   48 unix_syscall(struct savearea *regs);
   49 void
   50 unix_syscall_return(int error);
   51 
   52 extern struct savearea * 
   53 find_user_regs(
   54         thread_t act);
   55 
   56 extern void enter_funnel_section(funnel_t *funnel_lock);
   57 extern void exit_funnel_section(void);
   58 
   59 /*
   60  * Function:    unix_syscall
   61  *
   62  * Inputs:      regs    - pointer to Process Control Block
   63  *
   64  * Outputs:     none
   65  */
   66 void
   67 unix_syscall(struct savearea    *regs)
   68 {
   69         thread_t                        thread_act;
   70         struct uthread          *uthread;
   71         struct proc                     *proc;
   72         struct sysent           *callp;
   73         int                                     error;
   74         unsigned short          code;
   75         boolean_t                       flavor;
   76         int funnel_type;
   77         unsigned int cancel_enable;
   78 
   79         flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
   80 
   81         if (flavor)
   82                 code = regs->save_r3;
   83         else
   84                 code = regs->save_r0;
   85 
   86         if (kdebug_enable && (code != 180)) {
   87                 if (flavor)
   88                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
   89                                 regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0);
   90                 else
   91                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
   92                                 regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0);
   93         }
   94         thread_act = current_thread();
   95         uthread = get_bsdthread_info(thread_act);
   96 
   97         if (!(uthread->uu_flag & UT_VFORK))
   98                 proc = (struct proc *)get_bsdtask_info(current_task());
   99         else
  100                 proc = current_proc();
  101 
  102         /* Make sure there is a process associated with this task */
  103         if (proc == NULL) {
  104                 regs->save_r3 = (long long)EPERM;
  105                 /* set the "pc" to execute cerror routine */
  106                 regs->save_srr0 -= 4;
  107                 task_terminate_internal(current_task());
  108                 thread_exception_return();
  109                 /* NOTREACHED */
  110         }
  111 
  112         /*
  113          * Delayed binding of thread credential to process credential, if we
  114          * are not running with an explicitly set thread credential.
  115          */
  116         if (uthread->uu_ucred != proc->p_ucred &&
  117             (uthread->uu_flag & UT_SETUID) == 0) {
  118                 kauth_cred_t old = uthread->uu_ucred;
  119                 proc_lock(proc);
  120                 uthread->uu_ucred = proc->p_ucred;
  121                 kauth_cred_ref(uthread->uu_ucred);
  122                 proc_unlock(proc);
  123                 if (old != NOCRED)
  124                         kauth_cred_rele(old);
  125         }
  126 
  127         uthread->uu_ar0 = (int *)regs;
  128 
  129         callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
  130 
  131         if (callp->sy_narg != 0) {
  132                 void            *regsp;
  133                 sy_munge_t      *mungerp;
  134                 
  135                 if (IS_64BIT_PROCESS(proc)) {
  136                         /* XXX Turn 64 bit unsafe calls into nosys() */
  137                         if (callp->sy_funnel & UNSAFE_64BIT) {
  138                                 callp = &sysent[63];
  139                                 goto unsafe;
  140                         }
  141                         mungerp = callp->sy_arg_munge64;
  142                 }
  143                 else {
  144                         mungerp = callp->sy_arg_munge32;
  145                 }
  146                 if ( !flavor) {
  147                         regsp = (void *) &regs->save_r3;
  148                 } else {
  149                         /* indirect system call consumes an argument so only 7 are supported */
  150                         if (callp->sy_narg > 7) {
  151                                 callp = &sysent[63];
  152                                 goto unsafe;
  153                         }
  154                         regsp = (void *) &regs->save_r4;
  155                 }
  156                 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
  157                 (*mungerp)(regsp, (void *) &uthread->uu_arg[0]);
  158         }
  159 
  160 unsafe:
  161         cancel_enable = callp->sy_cancel;
  162         
  163         if (cancel_enable == _SYSCALL_CANCEL_NONE) {
  164                         uthread->uu_flag |= UT_NOTCANCELPT;
  165         } else {
  166                 if((uthread->uu_flag & (UT_CANCELDISABLE | UT_CANCEL | UT_CANCELED)) == UT_CANCEL) {
  167                         if (cancel_enable == _SYSCALL_CANCEL_PRE) {
  168                                         /* system call cancelled; return to handle cancellation */
  169                                         regs->save_r3 = (long long)EINTR;
  170                                         thread_exception_return();
  171                                         /* NOTREACHED */
  172                         } else {
  173                         thread_abort_safely(thread_act);
  174                         }
  175                 }
  176         }
  177 
  178         funnel_type = (int)(callp->sy_funnel & FUNNEL_MASK);
  179         if (funnel_type == KERNEL_FUNNEL) 
  180                  enter_funnel_section(kernel_flock);
  181         
  182         uthread->uu_rval[0] = 0;
  183 
  184         /*
  185          * r4 is volatile, if we set it to regs->save_r4 here the child
  186          * will have parents r4 after execve
  187          */
  188         uthread->uu_rval[1] = 0;
  189 
  190         error = 0;
  191 
  192         /*
  193          * PPC runtime calls cerror after every unix system call, so
  194          * assume no error and adjust the "pc" to skip this call.
  195          * It will be set back to the cerror call if an error is detected.
  196          */
  197         regs->save_srr0 += 4;
  198 
  199         if (KTRPOINT(proc, KTR_SYSCALL))
  200                 ktrsyscall(proc, code, callp->sy_narg, uthread->uu_arg);
  201 
  202 #ifdef JOE_DEBUG
  203         uthread->uu_iocount = 0;
  204         uthread->uu_vpindex = 0;
  205 #endif
  206         AUDIT_SYSCALL_ENTER(code, proc, uthread);
  207         error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0]));
  208         AUDIT_SYSCALL_EXIT(error, proc, uthread);
  209 
  210 #ifdef JOE_DEBUG
  211         if (uthread->uu_iocount)
  212                 joe_debug("system call returned with uu_iocount != 0");
  213 #endif
  214         regs = find_user_regs(thread_act);
  215 
  216         if (error == ERESTART) {
  217                 regs->save_srr0 -= 8;
  218         } else if (error != EJUSTRETURN) {
  219                 if (error) {
  220                         regs->save_r3 = (long long)error;
  221                         /* set the "pc" to execute cerror routine */
  222                         regs->save_srr0 -= 4;
  223                 } else { /* (not error) */
  224                         switch (callp->sy_return_type) {
  225                         case _SYSCALL_RET_INT_T:
  226                                 regs->save_r3 = uthread->uu_rval[0];
  227                                 regs->save_r4 = uthread->uu_rval[1];
  228                                 break;
  229                         case _SYSCALL_RET_UINT_T:
  230                                 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
  231                                 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
  232                                 break;
  233                         case _SYSCALL_RET_OFF_T:
  234                                 /* off_t returns 64 bits split across two registers for 32 bit */
  235                                 /* process and in one register for 64 bit process */
  236                                 if (IS_64BIT_PROCESS(proc)) {
  237                                         u_int64_t       *retp = (u_int64_t *)&uthread->uu_rval[0];
  238                                         regs->save_r3 = *retp;
  239                                         regs->save_r4 = 0;
  240                                 }
  241                                 else {
  242                                         regs->save_r3 = uthread->uu_rval[0];
  243                                         regs->save_r4 = uthread->uu_rval[1];
  244                                 }
  245                                 break;
  246                         case _SYSCALL_RET_ADDR_T:
  247                         case _SYSCALL_RET_SIZE_T:
  248                         case _SYSCALL_RET_SSIZE_T:
  249                                 /* the variable length return types (user_addr_t, user_ssize_t, 
  250                                  * and user_size_t) are always the largest possible size in the 
  251                                  * kernel (we use uu_rval[0] and [1] as one 64 bit value).
  252                                  */
  253                                 {
  254                                         user_addr_t *retp = (user_addr_t *)&uthread->uu_rval[0];
  255                                         regs->save_r3 = *retp;
  256                                         regs->save_r4 = 0;
  257                                 }
  258                                 break;
  259                         case _SYSCALL_RET_NONE:
  260                                 break;
  261                         default:
  262                                 panic("unix_syscall: unknown return type");
  263                                 break;
  264                         }
  265                 } 
  266         }
  267         /* else  (error == EJUSTRETURN) { nothing } */
  268 
  269 
  270         if (KTRPOINT(proc, KTR_SYSRET)) {
  271                 switch(callp->sy_return_type) {
  272                 case _SYSCALL_RET_ADDR_T:
  273                 case _SYSCALL_RET_SIZE_T:
  274                 case _SYSCALL_RET_SSIZE_T:
  275                         /*
  276                          * Trace the value of the least significant bits,
  277                          * until we can revise the ktrace API safely.
  278                          */
  279                         ktrsysret(proc, code, error, uthread->uu_rval[1]);
  280                         break;
  281                 default:
  282                         ktrsysret(proc, code, error, uthread->uu_rval[0]);
  283                         break;
  284                 }
  285         }
  286 
  287         if (cancel_enable == _SYSCALL_CANCEL_NONE)
  288                 uthread->uu_flag &= ~UT_NOTCANCELPT;
  289 
  290         exit_funnel_section();
  291 
  292         if (uthread->uu_lowpri_delay) {
  293                 /*
  294                  * task is marked as a low priority I/O type
  295                  * and the I/O we issued while in this system call
  296                  * collided with normal I/O operations... we'll
  297                  * delay in order to mitigate the impact of this
  298                  * task on the normal operation of the system
  299                  */
  300                 IOSleep(uthread->uu_lowpri_delay);
  301                 uthread->uu_lowpri_delay = 0;
  302         }
  303         if (kdebug_enable && (code != 180)) {
  304 
  305                 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
  306                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
  307                                               error, uthread->uu_rval[1], 0, 0, 0);
  308                 else
  309                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
  310                                               error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
  311         }
  312 
  313         thread_exception_return();
  314         /* NOTREACHED */
  315 }
  316 
  317 void
  318 unix_syscall_return(int error)
  319 {
  320         thread_t                                        thread_act;
  321         struct uthread                          *uthread;
  322         struct proc                                     *proc;
  323         struct savearea                         *regs;
  324         unsigned short                          code;
  325         struct sysent                           *callp;
  326         int funnel_type;
  327         unsigned int cancel_enable;
  328 
  329         thread_act = current_thread();
  330         proc = current_proc();
  331         uthread = get_bsdthread_info(thread_act);
  332 
  333         regs = find_user_regs(thread_act);
  334 
  335         if (regs->save_r0 != 0)
  336                 code = regs->save_r0;
  337         else
  338                 code = regs->save_r3;
  339 
  340         callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
  341 
  342         /*
  343          * Get index into sysent table
  344          */   
  345         if (error == ERESTART) {
  346                 regs->save_srr0 -= 8;
  347         } else if (error != EJUSTRETURN) {
  348                 if (error) {
  349                         regs->save_r3 = (long long)error;
  350                         /* set the "pc" to execute cerror routine */
  351                         regs->save_srr0 -= 4;
  352                 } else { /* (not error) */
  353                         switch (callp->sy_return_type) {
  354                         case _SYSCALL_RET_INT_T:
  355                                 regs->save_r3 = uthread->uu_rval[0];
  356                                 regs->save_r4 = uthread->uu_rval[1];
  357                                 break;
  358                         case _SYSCALL_RET_UINT_T:
  359                                 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
  360                                 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
  361                                 break;
  362                         case _SYSCALL_RET_OFF_T:
  363                                 /* off_t returns 64 bits split across two registers for 32 bit */
  364                                 /* process and in one register for 64 bit process */
  365                                 if (IS_64BIT_PROCESS(proc)) {
  366                                         u_int64_t       *retp = (u_int64_t *)&uthread->uu_rval[0];
  367                                         regs->save_r3 = *retp;
  368                                 }
  369                                 else {
  370                                         regs->save_r3 = uthread->uu_rval[0];
  371                                         regs->save_r4 = uthread->uu_rval[1];
  372                                 }
  373                                 break;
  374                         case _SYSCALL_RET_ADDR_T:
  375                         case _SYSCALL_RET_SIZE_T:
  376                         case _SYSCALL_RET_SSIZE_T:
  377                                 /* the variable length return types (user_addr_t, user_ssize_t, 
  378                                  * and user_size_t) are always the largest possible size in the 
  379                                  * kernel (we use uu_rval[0] and [1] as one 64 bit value).
  380                                  */
  381                                 {
  382                                         u_int64_t       *retp = (u_int64_t *)&uthread->uu_rval[0];
  383                                         regs->save_r3 = *retp;
  384                                 }
  385                                 break;
  386                         case _SYSCALL_RET_NONE:
  387                                 break;
  388                         default:
  389                                 panic("unix_syscall: unknown return type");
  390                                 break;
  391                         }
  392                 } 
  393         }
  394         /* else  (error == EJUSTRETURN) { nothing } */
  395 
  396         if (KTRPOINT(proc, KTR_SYSRET)) {
  397                 switch(callp->sy_return_type) {
  398                 case _SYSCALL_RET_ADDR_T:
  399                 case _SYSCALL_RET_SIZE_T:
  400                 case _SYSCALL_RET_SSIZE_T:
  401                         /*
  402                          * Trace the value of the least significant bits,
  403                          * until we can revise the ktrace API safely.
  404                          */
  405                         ktrsysret(proc, code, error, uthread->uu_rval[1]);
  406                         break;
  407                 default:
  408                         ktrsysret(proc, code, error, uthread->uu_rval[0]);
  409                         break;
  410                 }
  411         }
  412 
  413         cancel_enable = callp->sy_cancel;
  414 
  415         if (cancel_enable == _SYSCALL_CANCEL_NONE)
  416                 uthread->uu_flag &= ~UT_NOTCANCELPT;
  417 
  418         exit_funnel_section();
  419 
  420         if (uthread->uu_lowpri_delay) {
  421                 /*
  422                  * task is marked as a low priority I/O type
  423                  * and the I/O we issued while in this system call
  424                  * collided with normal I/O operations... we'll
  425                  * delay in order to mitigate the impact of this
  426                  * task on the normal operation of the system
  427                  */
  428                 IOSleep(uthread->uu_lowpri_delay);
  429                 uthread->uu_lowpri_delay = 0;
  430         }
  431         if (kdebug_enable && (code != 180)) {
  432                 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
  433                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
  434                                               error, uthread->uu_rval[1], 0, 0, 0);
  435                 else
  436                         KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
  437                                               error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
  438         }
  439 
  440         thread_exception_return();
  441         /* NOTREACHED */
  442 }
  443 
  444 /* 
  445  * Time of day and interval timer support.
  446  *
  447  * These routines provide the kernel entry points to get and set
  448  * the time-of-day and per-process interval timers.  Subroutines
  449  * here provide support for adding and subtracting timeval structures
  450  * and decrementing interval timers, optionally reloading the interval
  451  * timers when they expire.
  452  */
  453 /*  NOTE THIS implementation is for  ppc architectures only.
  454  *  It is infrequently called, since the commpage intercepts
  455  *  most calls in user mode.
  456  *
  457  * XXX Y2038 bug because of assumed return of 32 bit seconds value, and
  458  * XXX first parameter to clock_gettimeofday()
  459  */
  460 int
  461 ppc_gettimeofday(__unused struct proc *p, 
  462                                  register struct ppc_gettimeofday_args *uap, 
  463                                  register_t *retval)
  464 {
  465         int error = 0;
  466         extern lck_spin_t * tz_slock;
  467 
  468         if (uap->tp)
  469                 clock_gettimeofday(&retval[0], &retval[1]);
  470         
  471         if (uap->tzp) {
  472                 struct timezone ltz;
  473 
  474                 lck_spin_lock(tz_slock);
  475                 ltz = tz;
  476                 lck_spin_unlock(tz_slock);
  477                 error = copyout((caddr_t)&ltz, uap->tzp, sizeof (tz));
  478         }
  479 
  480         return (error);
  481 }
  482 
  483 #ifdef JOE_DEBUG
  484 joe_debug(char *p) {
  485 
  486         printf("%s\n", p);
  487 }
  488 #endif
  489 
  490 
  491 /* 
  492  * WARNING - this is a temporary workaround for binary compatibility issues
  493  * with anti-piracy software that relies on patching ptrace (3928003).
  494  * This KPI will be removed in the system release after Tiger.
  495  */
  496 uintptr_t temp_patch_ptrace(uintptr_t new_ptrace)
  497 {
  498         struct sysent *         callp;
  499         sy_call_t *                     old_ptrace;
  500 
  501         if (new_ptrace == 0)
  502                 return(0);
  503                 
  504         enter_funnel_section(kernel_flock);
  505         callp = &sysent[26];
  506         old_ptrace = callp->sy_call;
  507         
  508         /* only allow one patcher of ptrace */
  509         if (old_ptrace == (sy_call_t *) ptrace) {
  510                 callp->sy_call = (sy_call_t *) new_ptrace;
  511         }
  512         else {
  513                 old_ptrace = NULL;
  514         }
  515         exit_funnel_section( );
  516         
  517         return((uintptr_t)old_ptrace);
  518 }
  519 
  520 void temp_unpatch_ptrace(void)
  521 {
  522         struct sysent *         callp;
  523                 
  524         enter_funnel_section(kernel_flock);
  525         callp = &sysent[26];
  526         callp->sy_call = (sy_call_t *) ptrace;
  527         exit_funnel_section( );
  528         
  529         return;
  530 }

Cache object: 65f9707df86c7b93f1a8fd77950e72d6


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