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/osfmk/i386/pcb.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 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * @OSF_COPYRIGHT@
   27  */
   28 /* 
   29  * Mach Operating System
   30  * Copyright (c) 1991,1990 Carnegie Mellon University
   31  * All Rights Reserved.
   32  * 
   33  * Permission to use, copy, modify and distribute this software and its
   34  * documentation is hereby granted, provided that both the copyright
   35  * notice and this permission notice appear in all copies of the
   36  * software, derivative works or modified versions, and any portions
   37  * thereof, and that both notices appear in supporting documentation.
   38  * 
   39  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   40  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   41  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   42  * 
   43  * Carnegie Mellon requests users of this software to return to
   44  * 
   45  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   46  *  School of Computer Science
   47  *  Carnegie Mellon University
   48  *  Pittsburgh PA 15213-3890
   49  * 
   50  * any improvements or extensions that they make and grant Carnegie Mellon
   51  * the rights to redistribute these changes.
   52  */
   53 
   54 #include <cpus.h>
   55 #include <mach_rt.h>
   56 #include <mach_debug.h>
   57 #include <mach_ldebug.h>
   58 
   59 #include <sys/kdebug.h>
   60 
   61 #include <mach/kern_return.h>
   62 #include <mach/thread_status.h>
   63 #include <mach/vm_param.h>
   64 
   65 #include <kern/counters.h>
   66 #include <kern/mach_param.h>
   67 #include <kern/task.h>
   68 #include <kern/thread.h>
   69 #include <kern/thread_act.h>
   70 #include <kern/thread_swap.h>
   71 #include <kern/sched_prim.h>
   72 #include <kern/misc_protos.h>
   73 #include <kern/assert.h>
   74 #include <kern/spl.h>
   75 #include <ipc/ipc_port.h>
   76 #include <vm/vm_kern.h>
   77 #include <vm/pmap.h>
   78 
   79 #include <i386/thread.h>
   80 #include <i386/eflags.h>
   81 #include <i386/proc_reg.h>
   82 #include <i386/seg.h>
   83 #include <i386/tss.h>
   84 #include <i386/user_ldt.h>
   85 #include <i386/fpu.h>
   86 #include <i386/iopb_entries.h>
   87 
   88 vm_offset_t         active_stacks[NCPUS];
   89 vm_offset_t         kernel_stack[NCPUS];
   90 thread_act_t            active_kloaded[NCPUS];
   91 
   92 /*
   93  * Maps state flavor to number of words in the state:
   94  */
   95 unsigned int state_count[] = {
   96         /* FLAVOR_LIST */ 0,
   97         i386_NEW_THREAD_STATE_COUNT,
   98         i386_FLOAT_STATE_COUNT,
   99         i386_ISA_PORT_MAP_STATE_COUNT,
  100         i386_V86_ASSIST_STATE_COUNT,
  101         i386_REGS_SEGS_STATE_COUNT,
  102         i386_THREAD_SYSCALL_STATE_COUNT,
  103         /* THREAD_STATE_NONE */ 0,
  104         i386_SAVED_STATE_COUNT,
  105 };
  106 
  107 /* Forward */
  108 
  109 void act_machine_throughcall(thread_act_t thr_act);
  110 extern thread_t         Switch_context(
  111                                 thread_t                old,
  112                                 void                    (*cont)(void),
  113                                 thread_t                new);
  114 extern void             Thread_continue(void);
  115 extern void             Load_context(
  116                                 thread_t                thread);
  117 
  118 /*
  119  * consider_machine_collect:
  120  *
  121  *      Try to collect machine-dependent pages
  122  */
  123 void
  124 consider_machine_collect()
  125 {
  126 }
  127 
  128 void
  129 consider_machine_adjust()
  130 {
  131 }
  132 
  133 
  134 /*
  135  *      machine_kernel_stack_init:
  136  *
  137  *      Initialize a kernel stack which has already been
  138  *      attached to its thread_activation.
  139  */
  140 
  141 void
  142 machine_kernel_stack_init(
  143         thread_t        thread,
  144         void            (*start_pos)(thread_t))
  145 {
  146         thread_act_t    thr_act = thread->top_act;
  147         vm_offset_t     stack;
  148 
  149         assert(thr_act);
  150         stack = thread->kernel_stack;
  151         assert(stack);
  152 
  153         /*
  154          *      We want to run at start_pos, giving it as an argument
  155          *      the return value from Load_context/Switch_context.
  156          *      Thread_continue takes care of the mismatch between
  157          *      the argument-passing/return-value conventions.
  158          *      This function will not return normally,
  159          *      so we don`t have to worry about a return address.
  160          */
  161         STACK_IKS(stack)->k_eip = (int) Thread_continue;
  162         STACK_IKS(stack)->k_ebx = (int) start_pos;
  163         STACK_IKS(stack)->k_esp = (int) STACK_IEL(stack);
  164 
  165         /*
  166          *      Point top of kernel stack to user`s registers.
  167          */
  168         STACK_IEL(stack)->saved_state = &thr_act->mact.pcb->iss;
  169 }
  170 
  171 
  172 #if     NCPUS > 1
  173 #define curr_gdt(mycpu)         (mp_gdt[mycpu])
  174 #define curr_ldt(mycpu)         (mp_ldt[mycpu])
  175 #define curr_ktss(mycpu)        (mp_ktss[mycpu])
  176 #else
  177 #define curr_gdt(mycpu)         (gdt)
  178 #define curr_ldt(mycpu)         (ldt)
  179 #define curr_ktss(mycpu)        (&ktss)
  180 #endif
  181 
  182 #define gdt_desc_p(mycpu,sel) \
  183         ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
  184 
  185 void
  186 act_machine_switch_pcb( thread_act_t new_act )
  187 {
  188         pcb_t                   pcb = new_act->mact.pcb;
  189         int                     mycpu;
  190         register iopb_tss_t     tss = pcb->ims.io_tss;
  191         vm_offset_t             pcb_stack_top;
  192         register user_ldt_t     ldt = pcb->ims.ldt;
  193 
  194         assert(new_act->thread != NULL);
  195         assert(new_act->thread->kernel_stack != 0);
  196         STACK_IEL(new_act->thread->kernel_stack)->saved_state =
  197                 &new_act->mact.pcb->iss;
  198 
  199         /*
  200          *      Save a pointer to the top of the "kernel" stack -
  201          *      actually the place in the PCB where a trap into
  202          *      kernel mode will push the registers.
  203          *      The location depends on V8086 mode.  If we are
  204          *      not in V8086 mode, then a trap into the kernel
  205          *      won`t save the v86 segments, so we leave room.
  206          */
  207 
  208         pcb_stack_top = (pcb->iss.efl & EFL_VM)
  209                         ? (int) (&pcb->iss + 1)
  210                         : (int) (&pcb->iss.v86_segs);
  211 
  212         mp_disable_preemption();
  213         mycpu = cpu_number();
  214 
  215         if (tss == 0) {
  216             /*
  217              *  No per-thread IO permissions.
  218              *  Use standard kernel TSS.
  219              */
  220             if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
  221                 set_tr(KERNEL_TSS);
  222             curr_ktss(mycpu)->esp0 = pcb_stack_top;
  223         }
  224         else {
  225             /*
  226              * Set the IO permissions.  Use this thread`s TSS.
  227              */
  228             *gdt_desc_p(mycpu,USER_TSS)
  229                 = *(struct real_descriptor *)tss->iopb_desc;
  230             tss->tss.esp0 = pcb_stack_top;
  231             set_tr(USER_TSS);
  232             gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
  233         }
  234 
  235         /*
  236          * Set the thread`s LDT.
  237          */
  238         if (ldt == 0) {
  239             struct real_descriptor *ldtp;
  240             /*
  241              * Use system LDT.
  242              */
  243             ldtp = (struct real_descriptor *)curr_ldt(mycpu);
  244             ldtp[sel_idx(USER_CTHREAD)] = pcb->cthread_desc;
  245             set_ldt(KERNEL_LDT);
  246         }
  247         else {
  248             /*
  249              * Thread has its own LDT.
  250              */
  251             *gdt_desc_p(mycpu,USER_LDT) = ldt->desc;
  252             set_ldt(USER_LDT);
  253         }
  254 
  255         mp_enable_preemption();
  256         /*
  257          * Load the floating-point context, if necessary.
  258          */
  259         fpu_load_context(pcb);
  260 
  261 }
  262 
  263 /*
  264  * Switch to the first thread on a CPU.
  265  */
  266 void
  267 machine_load_context(
  268         thread_t                new)
  269 {
  270         act_machine_switch_pcb(new->top_act);
  271         Load_context(new);
  272 }
  273 
  274 /*
  275  * Number of times we needed to swap an activation back in before
  276  * switching to it.
  277  */
  278 int switch_act_swapins = 0;
  279 
  280 /*
  281  * machine_switch_act
  282  *
  283  * Machine-dependent details of activation switching.  Called with
  284  * RPC locks held and preemption disabled.
  285  */
  286 void
  287 machine_switch_act( 
  288         thread_t        thread,
  289         thread_act_t    old,
  290         thread_act_t    new)
  291 {
  292         int             cpu = cpu_number();
  293 
  294         /*
  295          *      Switch the vm, ast and pcb context. 
  296          *      Save FP registers if in use and set TS (task switch) bit.
  297          */
  298         fpu_save_context(thread);
  299 
  300         active_stacks[cpu] = thread->kernel_stack;
  301         ast_context(new, cpu);
  302 
  303         PMAP_SWITCH_CONTEXT(old, new, cpu);
  304         act_machine_switch_pcb(new);
  305 }
  306 
  307 /*
  308  * Switch to a new thread.
  309  * Save the old thread`s kernel state or continuation,
  310  * and return it.
  311  */
  312 thread_t
  313 machine_switch_context(
  314         thread_t                old,
  315         void                    (*continuation)(void),
  316         thread_t                new)
  317 {
  318         register thread_act_t   old_act = old->top_act,
  319                                 new_act = new->top_act;
  320 
  321 #if MACH_RT
  322         assert(active_stacks[cpu_number()] == old_act->thread->kernel_stack);
  323 #endif
  324         check_simple_locks();
  325 
  326         /*
  327          *      Save FP registers if in use.
  328          */
  329         fpu_save_context(old);
  330 
  331         /*
  332          *      Switch address maps if need be, even if not switching tasks.
  333          *      (A server activation may be "borrowing" a client map.)
  334          */
  335     {
  336         int     mycpu = cpu_number();
  337 
  338         PMAP_SWITCH_CONTEXT(old_act, new_act, mycpu)
  339     }
  340 
  341         /*
  342          *      Load the rest of the user state for the new thread
  343          */
  344         act_machine_switch_pcb(new_act);
  345         KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE,
  346                      (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
  347         old->continuation = NULL;
  348         return(Switch_context(old, continuation, new));
  349 }
  350 
  351 /*
  352  * act_machine_sv_free
  353  * release saveareas associated with an act. if flag is true, release
  354  * user level savearea(s) too, else don't
  355  */
  356 void
  357 act_machine_sv_free(thread_act_t act, int flag)
  358 {
  359 }
  360 
  361 /*
  362  *      act_machine_set_state:
  363  *
  364  *      Set the status of the specified thread.  Called with "appropriate"
  365  *      thread-related locks held (see act_lock_thread()), so
  366  *      thr_act->thread is guaranteed not to change.
  367  */
  368 
  369 kern_return_t
  370 machine_thread_set_state(
  371         thread_act_t thr_act,
  372         thread_flavor_t flavor,
  373         thread_state_t tstate,
  374         mach_msg_type_number_t count)
  375 {
  376         int kernel_act = 0;
  377 
  378         switch (flavor) {
  379             case THREAD_SYSCALL_STATE:
  380             {
  381                 register struct thread_syscall_state *state;
  382                 register struct i386_saved_state *saved_state = USER_REGS(thr_act);
  383 
  384                 state = (struct thread_syscall_state *) tstate;
  385                 saved_state->eax = state->eax;
  386                 saved_state->edx = state->edx;
  387                 if (kernel_act)
  388                         saved_state->efl = state->efl;
  389                 else
  390                         saved_state->efl = (state->efl & ~EFL_USER_CLEAR) | EFL_USER_SET;
  391                 saved_state->eip = state->eip;
  392                 saved_state->uesp = state->esp;
  393                 break;
  394             }
  395 
  396             case i386_SAVED_STATE:
  397             {
  398                 register struct i386_saved_state        *state;
  399                 register struct i386_saved_state        *saved_state;
  400 
  401                 if (count < i386_SAVED_STATE_COUNT) {
  402                     return(KERN_INVALID_ARGUMENT);
  403                 }
  404 
  405                 state = (struct i386_saved_state *) tstate;
  406 
  407                 saved_state = USER_REGS(thr_act);
  408 
  409                 /*
  410                  * General registers
  411                  */
  412                 saved_state->edi = state->edi;
  413                 saved_state->esi = state->esi;
  414                 saved_state->ebp = state->ebp;
  415                 saved_state->uesp = state->uesp;
  416                 saved_state->ebx = state->ebx;
  417                 saved_state->edx = state->edx;
  418                 saved_state->ecx = state->ecx;
  419                 saved_state->eax = state->eax;
  420                 saved_state->eip = state->eip;
  421                 if (kernel_act)
  422                         saved_state->efl = state->efl;
  423                 else
  424                         saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
  425                                                 | EFL_USER_SET;
  426 
  427                 /*
  428                  * Segment registers.  Set differently in V8086 mode.
  429                  */
  430                 if (state->efl & EFL_VM) {
  431                     /*
  432                      * Set V8086 mode segment registers.
  433                      */
  434                     saved_state->cs = state->cs & 0xffff;
  435                     saved_state->ss = state->ss & 0xffff;
  436                     saved_state->v86_segs.v86_ds = state->ds & 0xffff;
  437                     saved_state->v86_segs.v86_es = state->es & 0xffff;
  438                     saved_state->v86_segs.v86_fs = state->fs & 0xffff;
  439                     saved_state->v86_segs.v86_gs = state->gs & 0xffff;
  440 
  441                     /*
  442                      * Zero protected mode segment registers.
  443                      */
  444                     saved_state->ds = 0;
  445                     saved_state->es = 0;
  446                     saved_state->fs = 0;
  447                     saved_state->gs = 0;
  448 
  449                     if (thr_act->mact.pcb->ims.v86s.int_table) {
  450                         /*
  451                          * Hardware assist on.
  452                          */
  453                         thr_act->mact.pcb->ims.v86s.flags =
  454                             state->efl & (EFL_TF | EFL_IF);
  455                     }
  456                 }
  457                 else if (kernel_act) {
  458                     /*
  459                      * 386 mode.  Set segment registers for flat
  460                      * 32-bit address space.
  461                      */
  462                   saved_state->cs = KERNEL_CS;
  463                   saved_state->ss = KERNEL_DS;
  464                   saved_state->ds = KERNEL_DS;
  465                   saved_state->es = KERNEL_DS;
  466                   saved_state->fs = KERNEL_DS;
  467                   saved_state->gs = CPU_DATA;
  468                 }
  469                 else {
  470                     /*
  471                      * User setting segment registers.
  472                      * Code and stack selectors have already been
  473                      * checked.  Others will be reset by 'iret'
  474                      * if they are not valid.
  475                      */
  476                     saved_state->cs = state->cs;
  477                     saved_state->ss = state->ss;
  478                     saved_state->ds = state->ds;
  479                     saved_state->es = state->es;
  480                     saved_state->fs = state->fs;
  481                     saved_state->gs = state->gs;
  482                 }
  483                 break;
  484             }
  485 
  486             case i386_NEW_THREAD_STATE:
  487             case i386_REGS_SEGS_STATE:
  488             {
  489                 register struct i386_new_thread_state   *state;
  490                 register struct i386_saved_state        *saved_state;
  491 
  492                 if (count < i386_NEW_THREAD_STATE_COUNT) {
  493                     return(KERN_INVALID_ARGUMENT);
  494                 }
  495 
  496                 if (flavor == i386_REGS_SEGS_STATE) {
  497                     /*
  498                      * Code and stack selectors must not be null,
  499                      * and must have user protection levels.
  500                      * Only the low 16 bits are valid.
  501                      */
  502                     state->cs &= 0xffff;
  503                     state->ss &= 0xffff;
  504                     state->ds &= 0xffff;
  505                     state->es &= 0xffff;
  506                     state->fs &= 0xffff;
  507                     state->gs &= 0xffff;
  508 
  509                     if (!kernel_act &&
  510                         (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U
  511                         || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U))
  512                         return KERN_INVALID_ARGUMENT;
  513                 }
  514 
  515                 state = (struct i386_new_thread_state *) tstate;
  516 
  517                 saved_state = USER_REGS(thr_act);
  518 
  519                 /*
  520                  * General registers
  521                  */
  522                 saved_state->edi = state->edi;
  523                 saved_state->esi = state->esi;
  524                 saved_state->ebp = state->ebp;
  525                 saved_state->uesp = state->uesp;
  526                 saved_state->ebx = state->ebx;
  527                 saved_state->edx = state->edx;
  528                 saved_state->ecx = state->ecx;
  529                 saved_state->eax = state->eax;
  530                 saved_state->eip = state->eip;
  531                 if (kernel_act)
  532                         saved_state->efl = state->efl;
  533                 else
  534                         saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
  535                                                 | EFL_USER_SET;
  536 
  537                 /*
  538                  * Segment registers.  Set differently in V8086 mode.
  539                  */
  540                 if (state->efl & EFL_VM) {
  541                     /*
  542                      * Set V8086 mode segment registers.
  543                      */
  544                     saved_state->cs = state->cs & 0xffff;
  545                     saved_state->ss = state->ss & 0xffff;
  546                     saved_state->v86_segs.v86_ds = state->ds & 0xffff;
  547                     saved_state->v86_segs.v86_es = state->es & 0xffff;
  548                     saved_state->v86_segs.v86_fs = state->fs & 0xffff;
  549                     saved_state->v86_segs.v86_gs = state->gs & 0xffff;
  550 
  551                     /*
  552                      * Zero protected mode segment registers.
  553                      */
  554                     saved_state->ds = 0;
  555                     saved_state->es = 0;
  556                     saved_state->fs = 0;
  557                     saved_state->gs = 0;
  558 
  559                     if (thr_act->mact.pcb->ims.v86s.int_table) {
  560                         /*
  561                          * Hardware assist on.
  562                          */
  563                         thr_act->mact.pcb->ims.v86s.flags =
  564                             state->efl & (EFL_TF | EFL_IF);
  565                     }
  566                 }
  567                 else if (flavor == i386_NEW_THREAD_STATE && kernel_act) {
  568                     /*
  569                      * 386 mode.  Set segment registers for flat
  570                      * 32-bit address space.
  571                      */
  572                   saved_state->cs = KERNEL_CS;
  573                   saved_state->ss = KERNEL_DS;
  574                   saved_state->ds = KERNEL_DS;
  575                   saved_state->es = KERNEL_DS;
  576                   saved_state->fs = KERNEL_DS;
  577                   saved_state->gs = CPU_DATA;
  578                 }
  579                 else {
  580                     /*
  581                      * User setting segment registers.
  582                      * Code and stack selectors have already been
  583                      * checked.  Others will be reset by 'iret'
  584                      * if they are not valid.
  585                      */
  586                     saved_state->cs = state->cs;
  587                     saved_state->ss = state->ss;
  588                     saved_state->ds = state->ds;
  589                     saved_state->es = state->es;
  590                     saved_state->fs = state->fs;
  591                     saved_state->gs = state->gs;
  592                 }
  593                 break;
  594             }
  595 
  596             case i386_FLOAT_STATE: {
  597                 struct i386_float_state *state = (struct i386_float_state*)tstate;
  598                 if (count < i386_old_FLOAT_STATE_COUNT)
  599                         return(KERN_INVALID_ARGUMENT);
  600                 if (count < i386_FLOAT_STATE_COUNT)
  601                     return fpu_set_state(thr_act,(struct i386_float_state*)tstate);
  602                 else return fpu_set_fxstate(thr_act,(struct i386_float_state*)tstate);
  603             }
  604 
  605             /*
  606              * Temporary - replace by i386_io_map
  607              */
  608             case i386_ISA_PORT_MAP_STATE: {
  609                 register struct i386_isa_port_map_state *state;
  610                 register iopb_tss_t     tss;
  611 
  612                 if (count < i386_ISA_PORT_MAP_STATE_COUNT)
  613                         return(KERN_INVALID_ARGUMENT);
  614 
  615                 break;
  616             }
  617 
  618             case i386_V86_ASSIST_STATE:
  619             {
  620                 register struct i386_v86_assist_state *state;
  621                 vm_offset_t     int_table;
  622                 int             int_count;
  623 
  624                 if (count < i386_V86_ASSIST_STATE_COUNT)
  625                     return KERN_INVALID_ARGUMENT;
  626 
  627                 state = (struct i386_v86_assist_state *) tstate;
  628                 int_table = state->int_table;
  629                 int_count = state->int_count;
  630 
  631                 if (int_table >= VM_MAX_ADDRESS ||
  632                     int_table +
  633                         int_count * sizeof(struct v86_interrupt_table)
  634                             > VM_MAX_ADDRESS)
  635                     return KERN_INVALID_ARGUMENT;
  636 
  637                 thr_act->mact.pcb->ims.v86s.int_table = int_table;
  638                 thr_act->mact.pcb->ims.v86s.int_count = int_count;
  639 
  640                 thr_act->mact.pcb->ims.v86s.flags =
  641                         USER_REGS(thr_act)->efl & (EFL_TF | EFL_IF);
  642                 break;
  643             }
  644 
  645         case i386_THREAD_STATE: {
  646                 struct i386_saved_state *saved_state;
  647                 i386_thread_state_t     *state25;
  648 
  649                 saved_state = USER_REGS(thr_act);
  650                 state25 = (i386_thread_state_t *)tstate;
  651 
  652                 saved_state->eax = state25->eax;
  653                 saved_state->ebx = state25->ebx;
  654                 saved_state->ecx = state25->ecx;
  655                 saved_state->edx = state25->edx;
  656                 saved_state->edi = state25->edi;
  657                 saved_state->esi = state25->esi;
  658                 saved_state->ebp = state25->ebp;
  659                 saved_state->uesp = state25->esp;
  660                 saved_state->efl = (state25->eflags & ~EFL_USER_CLEAR)
  661                                                 | EFL_USER_SET;
  662                 saved_state->eip = state25->eip;
  663                 saved_state->cs = USER_CS;      /* FIXME? */
  664                 saved_state->ss = USER_DS;
  665                 saved_state->ds = USER_DS;
  666                 saved_state->es = USER_DS;
  667                 saved_state->fs = state25->fs;
  668                 saved_state->gs = state25->gs;
  669         }
  670                 break;
  671 
  672             default:
  673                 return(KERN_INVALID_ARGUMENT);
  674         }
  675 
  676         return(KERN_SUCCESS);
  677 }
  678 
  679 /*
  680  *      thread_getstatus:
  681  *
  682  *      Get the status of the specified thread.
  683  */
  684 
  685 
  686 kern_return_t
  687 machine_thread_get_state(
  688         thread_act_t thr_act,
  689         thread_flavor_t flavor,
  690         thread_state_t tstate,
  691         mach_msg_type_number_t *count)
  692 {
  693         switch (flavor)  {
  694 
  695             case i386_SAVED_STATE:
  696             {
  697                 register struct i386_saved_state        *state;
  698                 register struct i386_saved_state        *saved_state;
  699 
  700                 if (*count < i386_SAVED_STATE_COUNT)
  701                     return(KERN_INVALID_ARGUMENT);
  702 
  703                 state = (struct i386_saved_state *) tstate;
  704                 saved_state = USER_REGS(thr_act);
  705 
  706                 /*
  707                  * First, copy everything:
  708                  */
  709                 *state = *saved_state;
  710 
  711                 if (saved_state->efl & EFL_VM) {
  712                     /*
  713                      * V8086 mode.
  714                      */
  715                     state->ds = saved_state->v86_segs.v86_ds & 0xffff;
  716                     state->es = saved_state->v86_segs.v86_es & 0xffff;
  717                     state->fs = saved_state->v86_segs.v86_fs & 0xffff;
  718                     state->gs = saved_state->v86_segs.v86_gs & 0xffff;
  719 
  720                     if (thr_act->mact.pcb->ims.v86s.int_table) {
  721                         /*
  722                          * Hardware assist on
  723                          */
  724                         if ((thr_act->mact.pcb->ims.v86s.flags &
  725                                         (EFL_IF|V86_IF_PENDING)) == 0)
  726                             state->efl &= ~EFL_IF;
  727                     }
  728                 }
  729                 else {
  730                     /*
  731                      * 386 mode.
  732                      */
  733                     state->ds = saved_state->ds & 0xffff;
  734                     state->es = saved_state->es & 0xffff;
  735                     state->fs = saved_state->fs & 0xffff;
  736                     state->gs = saved_state->gs & 0xffff;
  737                 }
  738                 *count = i386_SAVED_STATE_COUNT;
  739                 break;
  740             }
  741 
  742             case i386_NEW_THREAD_STATE:
  743             case i386_REGS_SEGS_STATE:
  744             {
  745                 register struct i386_new_thread_state   *state;
  746                 register struct i386_saved_state        *saved_state;
  747 
  748                 if (*count < i386_NEW_THREAD_STATE_COUNT)
  749                     return(KERN_INVALID_ARGUMENT);
  750 
  751                 state = (struct i386_new_thread_state *) tstate;
  752                 saved_state = USER_REGS(thr_act);
  753 
  754                 /*
  755                  * General registers.
  756                  */
  757                 state->edi = saved_state->edi;
  758                 state->esi = saved_state->esi;
  759                 state->ebp = saved_state->ebp;
  760                 state->ebx = saved_state->ebx;
  761                 state->edx = saved_state->edx;
  762                 state->ecx = saved_state->ecx;
  763                 state->eax = saved_state->eax;
  764                 state->eip = saved_state->eip;
  765                 state->efl = saved_state->efl;
  766                 state->uesp = saved_state->uesp;
  767 
  768                 state->cs = saved_state->cs;
  769                 state->ss = saved_state->ss;
  770                 if (saved_state->efl & EFL_VM) {
  771                     /*
  772                      * V8086 mode.
  773                      */
  774                     state->ds = saved_state->v86_segs.v86_ds & 0xffff;
  775                     state->es = saved_state->v86_segs.v86_es & 0xffff;
  776                     state->fs = saved_state->v86_segs.v86_fs & 0xffff;
  777                     state->gs = saved_state->v86_segs.v86_gs & 0xffff;
  778 
  779                     if (thr_act->mact.pcb->ims.v86s.int_table) {
  780                         /*
  781                          * Hardware assist on
  782                          */
  783                         if ((thr_act->mact.pcb->ims.v86s.flags &
  784                                         (EFL_IF|V86_IF_PENDING)) == 0)
  785                             state->efl &= ~EFL_IF;
  786                     }
  787                 }
  788                 else {
  789                     /*
  790                      * 386 mode.
  791                      */
  792                     state->ds = saved_state->ds & 0xffff;
  793                     state->es = saved_state->es & 0xffff;
  794                     state->fs = saved_state->fs & 0xffff;
  795                     state->gs = saved_state->gs & 0xffff;
  796                 }
  797                 *count = i386_NEW_THREAD_STATE_COUNT;
  798                 break;
  799             }
  800 
  801             case THREAD_SYSCALL_STATE:
  802             {
  803                 register struct thread_syscall_state *state;
  804                 register struct i386_saved_state *saved_state = USER_REGS(thr_act);
  805 
  806                 state = (struct thread_syscall_state *) tstate;
  807                 state->eax = saved_state->eax;
  808                 state->edx = saved_state->edx;
  809                 state->efl = saved_state->efl;
  810                 state->eip = saved_state->eip;
  811                 state->esp = saved_state->uesp;
  812                 *count = i386_THREAD_SYSCALL_STATE_COUNT;
  813                 break;
  814             }
  815 
  816             case THREAD_STATE_FLAVOR_LIST:
  817                 if (*count < 5)
  818                     return (KERN_INVALID_ARGUMENT);
  819                 tstate[0] = i386_NEW_THREAD_STATE;
  820                 tstate[1] = i386_FLOAT_STATE;
  821                 tstate[2] = i386_ISA_PORT_MAP_STATE;
  822                 tstate[3] = i386_V86_ASSIST_STATE;
  823                 tstate[4] = THREAD_SYSCALL_STATE;
  824                 *count = 5;
  825                 break;
  826 
  827             case i386_FLOAT_STATE: {
  828                 struct i386_float_state *state = (struct i386_float_state*)tstate;
  829 
  830                 if (*count < i386_old_FLOAT_STATE_COUNT)
  831                         return(KERN_INVALID_ARGUMENT);
  832                 if (*count< i386_FLOAT_STATE_COUNT) {
  833                     *count = i386_old_FLOAT_STATE_COUNT;
  834                     return fpu_get_state(thr_act,(struct i386_float_state *)tstate);
  835                 } else {
  836                     *count = i386_FLOAT_STATE_COUNT;
  837                     return fpu_get_fxstate(thr_act,(struct i386_float_state *)tstate);
  838                 }
  839             }
  840 
  841             /*
  842              * Temporary - replace by i386_io_map
  843              */
  844             case i386_ISA_PORT_MAP_STATE: {
  845                 register struct i386_isa_port_map_state *state;
  846                 register iopb_tss_t tss;
  847 
  848                 if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
  849                         return(KERN_INVALID_ARGUMENT);
  850 
  851                 state = (struct i386_isa_port_map_state *) tstate;
  852                 tss = thr_act->mact.pcb->ims.io_tss;
  853 
  854                 if (tss == 0) {
  855                     int i;
  856 
  857                     /*
  858                      *  The thread has no ktss, so no IO permissions.
  859                      */
  860 
  861                     for (i = 0; i < sizeof state->pm; i++)
  862                         state->pm[i] = 0xff;
  863                 } else {
  864                     /*
  865                      *  The thread has its own ktss.
  866                      */
  867 
  868                     bcopy((char *) tss->bitmap,
  869                           (char *) state->pm,
  870                           sizeof state->pm);
  871                 }
  872 
  873                 *count = i386_ISA_PORT_MAP_STATE_COUNT;
  874                 break;
  875             }
  876 
  877             case i386_V86_ASSIST_STATE:
  878             {
  879                 register struct i386_v86_assist_state *state;
  880 
  881                 if (*count < i386_V86_ASSIST_STATE_COUNT)
  882                     return KERN_INVALID_ARGUMENT;
  883 
  884                 state = (struct i386_v86_assist_state *) tstate;
  885                 state->int_table = thr_act->mact.pcb->ims.v86s.int_table;
  886                 state->int_count = thr_act->mact.pcb->ims.v86s.int_count;
  887 
  888                 *count = i386_V86_ASSIST_STATE_COUNT;
  889                 break;
  890             }
  891 
  892         case i386_THREAD_STATE: {
  893                 struct i386_saved_state *saved_state;
  894                 i386_thread_state_t     *state;
  895 
  896                 saved_state = USER_REGS(thr_act);
  897                 state = (i386_thread_state_t *)tstate;
  898 
  899                 state->eax = saved_state->eax;
  900                 state->ebx = saved_state->ebx;
  901                 state->ecx = saved_state->ecx;
  902                 state->edx = saved_state->edx;
  903                 state->edi = saved_state->edi;
  904                 state->esi = saved_state->esi;
  905                 state->ebp = saved_state->ebp;
  906                 state->esp = saved_state->uesp;
  907                 state->eflags = saved_state->efl;
  908                 state->eip = saved_state->eip;
  909                 state->cs = saved_state->cs;
  910                 state->ss = saved_state->ss;
  911                 state->ds = saved_state->ds;
  912                 state->es = saved_state->es;
  913                 state->fs = saved_state->fs;
  914                 state->gs = saved_state->gs;
  915                 break;
  916         }
  917 
  918             default:
  919                 return(KERN_INVALID_ARGUMENT);
  920         }
  921 
  922         return(KERN_SUCCESS);
  923 }
  924 
  925 /*
  926  * Initialize the machine-dependent state for a new thread.
  927  */
  928 kern_return_t
  929 machine_thread_create(
  930         thread_t                thread,
  931         task_t                  task)
  932 {
  933         pcb_t   pcb = &thread->mact.xxx_pcb;
  934 
  935         thread->mact.pcb = pcb;
  936 
  937         simple_lock_init(&pcb->lock, ETAP_MISC_PCB);
  938 
  939         /*
  940          *      Guarantee that the bootstrapped thread will be in user
  941          *      mode.
  942          */
  943         pcb->iss.cs = USER_CS;
  944         pcb->iss.ss = USER_DS;
  945         pcb->iss.ds = USER_DS;
  946         pcb->iss.es = USER_DS;
  947         pcb->iss.fs = USER_DS;
  948         pcb->iss.gs = USER_DS;
  949         pcb->iss.efl = EFL_USER_SET;
  950         {
  951           extern struct fake_descriptor ldt[];
  952           struct real_descriptor *ldtp;
  953           ldtp = (struct real_descriptor *)ldt;
  954           pcb->cthread_desc = ldtp[sel_idx(USER_DS)];
  955         }
  956 
  957         /*
  958          *      Allocate a kernel stack per shuttle
  959          */
  960         thread->kernel_stack = (int)stack_alloc(thread, thread_continue);
  961         thread->state &= ~TH_STACK_HANDOFF;
  962         assert(thread->kernel_stack != 0);
  963 
  964         /*
  965          *      Point top of kernel stack to user`s registers.
  966          */
  967         STACK_IEL(thread->kernel_stack)->saved_state = &pcb->iss;
  968 
  969         return(KERN_SUCCESS);
  970 }
  971 
  972 /*
  973  * Machine-dependent cleanup prior to destroying a thread
  974  */
  975 void
  976 machine_thread_destroy(
  977         thread_t                thread)
  978 {
  979         register pcb_t  pcb = thread->mact.pcb;
  980 
  981         assert(pcb);
  982 
  983         if (pcb->ims.io_tss != 0)
  984                 iopb_destroy(pcb->ims.io_tss);
  985         if (pcb->ims.ifps != 0)
  986                 fp_free(pcb->ims.ifps);
  987         if (pcb->ims.ldt != 0)
  988                 user_ldt_free(pcb->ims.ldt);
  989         thread->mact.pcb = (pcb_t)0;
  990 }
  991 
  992 /*
  993  * This is used to set the current thr_act/thread
  994  * when starting up a new processor
  995  */
  996 void
  997 machine_thread_set_current( thread_t thread )
  998 {
  999         register int    my_cpu;
 1000 
 1001         mp_disable_preemption();
 1002         my_cpu = cpu_number();
 1003 
 1004         cpu_data[my_cpu].active_thread = thread->top_act;
 1005                 active_kloaded[my_cpu] = THR_ACT_NULL;
 1006 
 1007         mp_enable_preemption();
 1008 }
 1009 
 1010 void
 1011 machine_thread_terminate_self(void)
 1012 {
 1013 }
 1014 
 1015 void
 1016 act_machine_return(int code)
 1017 {
 1018         thread_act_t    thr_act = current_act();
 1019 
 1020         /*
 1021          * This code is called with nothing locked.
 1022          * It also returns with nothing locked, if it returns.
 1023          *
 1024          * This routine terminates the current thread activation.
 1025          * If this is the only activation associated with its
 1026          * thread shuttle, then the entire thread (shuttle plus
 1027          * activation) is terminated.
 1028          */
 1029         assert( code == KERN_TERMINATED );
 1030         assert( thr_act );
 1031 
 1032         /* This is the only activation attached to the shuttle... */
 1033         /* terminate the entire thread (shuttle plus activation) */
 1034 
 1035         assert(thr_act->thread->top_act == thr_act);
 1036         thread_terminate_self();
 1037 
 1038         /*NOTREACHED*/
 1039 
 1040         panic("act_machine_return: TALKING ZOMBIE! (1)");
 1041 }
 1042 
 1043 
 1044 /*
 1045  * Perform machine-dependent per-thread initializations
 1046  */
 1047 void
 1048 machine_thread_init(void)
 1049 {
 1050         fpu_module_init();
 1051         iopb_init();
 1052 }
 1053 
 1054 /*
 1055  * Some routines for debugging activation code
 1056  */
 1057 static void     dump_handlers(thread_act_t);
 1058 void    dump_regs(thread_act_t);
 1059 
 1060 static void
 1061 dump_handlers(thread_act_t thr_act)
 1062 {
 1063     ReturnHandler *rhp = thr_act->handlers;
 1064     int counter = 0;
 1065 
 1066     printf("\t");
 1067     while (rhp) {
 1068         if (rhp == &thr_act->special_handler){
 1069             if (rhp->next)
 1070                 printf("[NON-Zero next ptr(%x)]", rhp->next);
 1071             printf("special_handler()->");
 1072             break;
 1073         }
 1074         printf("hdlr_%d(%x)->",counter,rhp->handler);
 1075         rhp = rhp->next;
 1076         if (++counter > 32) {
 1077                 printf("Aborting: HUGE handler chain\n");
 1078                 break;
 1079         }
 1080     }
 1081     printf("HLDR_NULL\n");
 1082 }
 1083 
 1084 void
 1085 dump_regs(thread_act_t thr_act)
 1086 {
 1087         if (thr_act->mact.pcb) {
 1088                 register struct i386_saved_state *ssp = USER_REGS(thr_act);
 1089                 /* Print out user register state */
 1090                 printf("\tRegs:\tedi=%x esi=%x ebp=%x ebx=%x edx=%x\n",
 1091                     ssp->edi, ssp->esi, ssp->ebp, ssp->ebx, ssp->edx);
 1092                 printf("\t\tecx=%x eax=%x eip=%x efl=%x uesp=%x\n",
 1093                     ssp->ecx, ssp->eax, ssp->eip, ssp->efl, ssp->uesp);
 1094                 printf("\t\tcs=%x ss=%x\n", ssp->cs, ssp->ss);
 1095         }
 1096 }
 1097 
 1098 int
 1099 dump_act(thread_act_t thr_act)
 1100 {
 1101         if (!thr_act)
 1102                 return(0);
 1103 
 1104         printf("thr_act(0x%x)(%d): thread=%x(%d) task=%x(%d)\n",
 1105                thr_act, thr_act->ref_count,
 1106                thr_act->thread, thr_act->thread ? thr_act->thread->ref_count:0,
 1107                thr_act->task,   thr_act->task   ? thr_act->task->ref_count : 0);
 1108 
 1109         printf("\tsusp=%d user_stop=%d active=%x ast=%x\n",
 1110                        thr_act->suspend_count, thr_act->user_stop_count,
 1111                        thr_act->active, thr_act->ast);
 1112         printf("\thi=%x lo=%x\n", thr_act->higher, thr_act->lower);
 1113         printf("\tpcb=%x\n", thr_act->mact.pcb);
 1114 
 1115         if (thr_act->thread && thr_act->thread->kernel_stack) {
 1116             vm_offset_t stack = thr_act->thread->kernel_stack;
 1117 
 1118             printf("\tk_stk %x  eip %x ebx %x esp %x iss %x\n",
 1119                 stack, STACK_IKS(stack)->k_eip, STACK_IKS(stack)->k_ebx,
 1120                 STACK_IKS(stack)->k_esp, STACK_IEL(stack)->saved_state);
 1121         }
 1122 
 1123         dump_handlers(thr_act);
 1124         dump_regs(thr_act);
 1125         return((int)thr_act);
 1126 }
 1127 unsigned int
 1128 get_useraddr()
 1129 {
 1130   
 1131         thread_act_t thr_act = current_act();
 1132  
 1133         if (thr_act->mact.pcb) 
 1134                 return(thr_act->mact.pcb->iss.eip);
 1135         else 
 1136                 return(0);
 1137 
 1138 }
 1139 
 1140 void
 1141 thread_swapin_mach_alloc(thread_t thread)
 1142 {
 1143 
 1144   /* 386 does not have saveareas */
 1145 
 1146 }
 1147 /*
 1148  * detach and return a kernel stack from a thread
 1149  */
 1150 
 1151 vm_offset_t
 1152 machine_stack_detach(thread_t thread)
 1153 {
 1154   vm_offset_t stack;
 1155 
 1156                 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH),
 1157                         thread, thread->priority,
 1158                         thread->sched_pri, 0,
 1159                         0);
 1160 
 1161   stack = thread->kernel_stack;
 1162   thread->kernel_stack = 0;
 1163   return(stack);
 1164 }
 1165 
 1166 /*
 1167  * attach a kernel stack to a thread and initialize it
 1168  */
 1169 
 1170 void
 1171 machine_stack_attach(thread_t thread,
 1172              vm_offset_t stack,
 1173              void (*start_pos)(thread_t))
 1174 {
 1175   struct i386_kernel_state *statep;
 1176 
 1177                 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
 1178                         thread, thread->priority,
 1179                         thread->sched_pri, continuation, 
 1180                         0);
 1181 
 1182   assert(stack);
 1183   statep = STACK_IKS(stack);
 1184   thread->kernel_stack = stack;
 1185 
 1186   statep->k_eip = (unsigned long) Thread_continue;
 1187   statep->k_ebx = (unsigned long) start_pos;
 1188   statep->k_esp = (unsigned long) STACK_IEL(stack);
 1189 
 1190   STACK_IEL(stack)->saved_state = &thread->mact.pcb->iss;
 1191 
 1192   return;
 1193 }
 1194 
 1195 /*
 1196  * move a stack from old to new thread
 1197  */
 1198 
 1199 void
 1200 machine_stack_handoff(thread_t old,
 1201               thread_t new)
 1202 {
 1203 
 1204   vm_offset_t stack;
 1205 
 1206                 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF),
 1207                         thread, thread->priority,
 1208                         thread->sched_pri, continuation, 
 1209                         0);
 1210 
 1211   assert(new->top_act);
 1212   assert(old->top_act);
 1213 
 1214   stack = machine_stack_detach(old);
 1215   machine_stack_attach(new, stack, 0);
 1216 
 1217   PMAP_SWITCH_CONTEXT(old->top_act->task, new->top_act->task, cpu_number());
 1218 
 1219   KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE,
 1220                      (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
 1221 
 1222   machine_thread_set_current(new);
 1223 
 1224   active_stacks[cpu_number()] = new->kernel_stack;
 1225 
 1226   return;
 1227 }
 1228 
 1229 struct i386_act_context {
 1230         struct i386_saved_state ss;
 1231         struct i386_float_state fs;
 1232 };
 1233 
 1234 void *
 1235 act_thread_csave(void)
 1236 {
 1237 struct i386_act_context *ic;
 1238 kern_return_t kret;
 1239 int val;
 1240 
 1241                 ic = (struct i386_act_context *)kalloc(sizeof(struct i386_act_context));
 1242 
 1243                 if (ic == (struct i386_act_context *)NULL)
 1244                                 return((void *)0);
 1245 
 1246                 val = i386_SAVED_STATE_COUNT; 
 1247                 kret = machine_thread_get_state(current_act(),
 1248                                                 i386_SAVED_STATE,
 1249                                                 (thread_state_t) &ic->ss,
 1250                                                 &val);
 1251                 if (kret != KERN_SUCCESS) {
 1252                                 kfree((vm_offset_t)ic,sizeof(struct i386_act_context));
 1253                                 return((void *)0);
 1254                 }
 1255                 val = i386_FLOAT_STATE_COUNT; 
 1256                 kret = machine_thread_get_state(current_act(),
 1257                                                 i386_FLOAT_STATE,
 1258                                                 (thread_state_t) &ic->fs,
 1259                                                 &val);
 1260                 if (kret != KERN_SUCCESS) {
 1261                                 kfree((vm_offset_t)ic,sizeof(struct i386_act_context));
 1262                                 return((void *)0);
 1263                 }
 1264                 return(ic);
 1265 }
 1266 void 
 1267 act_thread_catt(void *ctx)
 1268 {
 1269 struct i386_act_context *ic;
 1270 kern_return_t kret;
 1271 int val;
 1272 
 1273                 ic = (struct i386_act_context *)ctx;
 1274 
 1275                 if (ic == (struct i386_act_context *)NULL)
 1276                                 return;
 1277 
 1278                 kret = machine_thread_set_state(current_act(),
 1279                                                 i386_SAVED_STATE,
 1280                                                 (thread_state_t) &ic->ss,
 1281                                                 i386_SAVED_STATE_COUNT);
 1282                 if (kret != KERN_SUCCESS) 
 1283                                 goto out;
 1284 
 1285                 kret = machine_thread_set_state(current_act(),
 1286                                                 i386_FLOAT_STATE,
 1287                                                 (thread_state_t) &ic->fs,
 1288                                                 i386_FLOAT_STATE_COUNT);
 1289                 if (kret != KERN_SUCCESS)
 1290                                 goto out;
 1291 out:
 1292         kfree((vm_offset_t)ic,sizeof(struct i386_act_context));         
 1293 }
 1294 
 1295 void act_thread_cfree(void *ctx)
 1296 {
 1297         kfree((vm_offset_t)ctx,sizeof(struct i386_act_context));                
 1298 }
 1299 

Cache object: 1515607b9edfbfae5b59a4a8007c61c7


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