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/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  * Mach Operating System
    3  * Copyright (c) 1991,1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        pcb.c,v $
   29  * Revision 2.14  93/01/14  17:29:21  danner
   30  *      Added include of mach/std_types.h
   31  *      [92/12/10  17:41:42  af]
   32  * 
   33  * Revision 2.13  92/01/03  20:08:34  dbg
   34  *      Disable thread_set_state of ISA_PORT_MAP, but have it still
   35  *      return KERN_SUCCESS (for DOS emulator compatibility).
   36  *      [91/12/06            dbg]
   37  * 
   38  *      Add user ldt management.  Move floating-point state
   39  *      manipulation to i386/fpu.{c,h}.
   40  * 
   41  *      Add user_stack_low and set_user_regs for passing control to
   42  *      bootstrap in user space.
   43  *      [91/10/30            dbg]
   44  * 
   45  * Revision 2.12  91/10/09  16:07:08  af
   46  *      Set value of kernel_stack field in stack_handoff().
   47  *      [91/08/29            tak]
   48  * 
   49  * Revision 2.11  91/07/31  17:39:56  dbg
   50  *      Add thread_set_syscall_return.
   51  * 
   52  *      Save user regs directly in PCB on trap, and switch to separate
   53  *      kernel stack.
   54  * 
   55  *      Add v8086 mode interrupt support.
   56  *      [91/07/30  16:56:09  dbg]
   57  * 
   58  * Revision 2.10  91/05/14  16:13:06  mrt
   59  *      Correcting copyright
   60  * 
   61  * Revision 2.9  91/05/08  12:40:34  dbg
   62  *      Use iopb_tss_t for IO permission bitmap.
   63  *      [91/03/21            dbg]
   64  * 
   65  * Revision 2.8  91/03/16  14:44:51  rpd
   66  *      Pulled i386_fpsave_state out of i386_machine_state.
   67  *      Added pcb_module_init.
   68  *      [91/02/18            rpd]
   69  * 
   70  *      Replaced stack_switch with stack_handoff and
   71  *      switch_task_context with switch_context.
   72  *      [91/02/18            rpd]
   73  *      Added active_stacks.
   74  *      [91/01/29            rpd]
   75  * 
   76  * Revision 2.7  91/02/05  17:13:19  mrt
   77  *      Changed to new Mach copyright
   78  *      [91/02/01  17:36:24  mrt]
   79  * 
   80  * Revision 2.6  91/01/09  22:41:41  rpd
   81  *      Revised the pcb yet again.
   82  *      Picked up i386_ISA_PORT_MAP_STATE flavors.
   83  *      Added load_context, switch_task_context cover functions.
   84  *      [91/01/09            rpd]
   85  * 
   86  * Revision 2.5  91/01/08  15:10:58  rpd
   87  *      Removed pcb_synch.  Added pcb_collect.
   88  *      [91/01/03            rpd]
   89  * 
   90  *      Split i386_machine_state off of i386_kernel_state.
   91  *      Set k_stack_top correctly for V8086 threads.
   92  *      [90/12/31            rpd]
   93  *      Added stack_switch.  Moved stack_alloc_try, stack_alloc,
   94  *      stack_free, stack_statistics to kern/thread.c.
   95  *      [90/12/14            rpd]
   96  * 
   97  *      Reorganized the pcb.
   98  *      Added stack_attach, stack_alloc, stack_alloc_try,
   99  *      stack_free, stack_statistics.
  100  *      [90/12/11            rpd]
  101  * 
  102  * Revision 2.4  90/08/27  21:57:34  dbg
  103  *      Return correct count from thread_getstatus.
  104  *      [90/08/22            dbg]
  105  * 
  106  * Revision 2.3  90/08/07  14:24:47  rpd
  107  *      Include seg.h for segment names.
  108  *      [90/07/17            dbg]
  109  * 
  110  * Revision 2.2  90/05/03  15:35:51  dbg
  111  *      Created.
  112  *      [90/02/08            dbg]
  113  * 
  114  */
  115 
  116 #include <cpus.h>
  117 #include <mach_debug.h>
  118 
  119 #include <mach/std_types.h>
  120 #include <mach/kern_return.h>
  121 #include <mach/thread_status.h>
  122 #include <mach/vm_param.h>
  123 
  124 #include <kern/counters.h>
  125 #include <kern/mach_param.h>
  126 #include <kern/thread.h>
  127 #include <kern/sched_prim.h>
  128 #include <vm/vm_kern.h>
  129 #include <vm/pmap.h>
  130 
  131 #include <i386/thread.h>
  132 #include <i386/eflags.h>
  133 #include <i386/proc_reg.h>
  134 #include <i386/seg.h>
  135 #include <i386/tss.h>
  136 #include <i386/user_ldt.h>
  137 #include <i386/fpu.h>
  138 
  139 #if     NCPUS > 1
  140 #include <i386/mp_desc.h>
  141 #endif
  142 
  143 extern thread_t Switch_context();
  144 extern void     Thread_continue();
  145 
  146 extern struct i386_tss          ktss;
  147 extern struct fake_descriptor   gdt[];
  148 
  149 extern iopb_tss_t       iopb_create();
  150 extern void             iopb_destroy();
  151 extern void             user_ldt_free();
  152 
  153 zone_t          pcb_zone;
  154 
  155 vm_offset_t     kernel_stack[NCPUS];    /* top of active_stack */
  156 
  157 /*
  158  *      stack_attach:
  159  *
  160  *      Attach a kernel stack to a thread.
  161  */
  162 
  163 void stack_attach(thread, stack, continuation)
  164         register thread_t thread;
  165         register vm_offset_t stack;
  166         void (*continuation)();
  167 {
  168         counter(if (++c_stacks_current > c_stacks_max)
  169                         c_stacks_max = c_stacks_current);
  170 
  171         thread->kernel_stack = stack;
  172 
  173         /*
  174          *      We want to run continuation, giving it as an argument
  175          *      the return value from Load_context/Switch_context.
  176          *      Thread_continue takes care of the mismatch between
  177          *      the argument-passing/return-value conventions.
  178          *      This function will not return normally,
  179          *      so we don`t have to worry about a return address.
  180          */
  181         STACK_IKS(stack)->k_eip = (int) Thread_continue;
  182         STACK_IKS(stack)->k_ebx = (int) continuation;
  183         STACK_IKS(stack)->k_esp = (int) STACK_IEL(stack);
  184 
  185         /*
  186          *      Point top of kernel stack to user`s registers.
  187          */
  188         STACK_IEL(stack)->saved_state = &thread->pcb->iss;
  189 }
  190 
  191 /*
  192  *      stack_detach:
  193  *
  194  *      Detaches a kernel stack from a thread, returning the old stack.
  195  */
  196 
  197 vm_offset_t stack_detach(thread)
  198         register thread_t       thread;
  199 {
  200         register vm_offset_t    stack;
  201 
  202         counter(if (--c_stacks_current < c_stacks_min)
  203                         c_stacks_min = c_stacks_current);
  204 
  205         stack = thread->kernel_stack;
  206         thread->kernel_stack = 0;
  207 
  208         return stack;
  209 }
  210 
  211 #if     NCPUS > 1
  212 #define curr_gdt(mycpu)         (mp_gdt[mycpu])
  213 #define curr_ktss(mycpu)        (mp_ktss[mycpu])
  214 #else
  215 #define curr_gdt(mycpu)         (gdt)
  216 #define curr_ktss(mycpu)        (&ktss)
  217 #endif
  218 
  219 #define gdt_desc_p(mycpu,sel) \
  220         ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
  221 
  222 void switch_ktss(pcb)
  223         register pcb_t  pcb;
  224 {
  225         int                     mycpu = cpu_number();
  226     {
  227         register iopb_tss_t     tss = pcb->ims.io_tss;
  228         vm_offset_t             pcb_stack_top;
  229 
  230         /*
  231          *      Save a pointer to the top of the "kernel" stack -
  232          *      actually the place in the PCB where a trap into
  233          *      kernel mode will push the registers.
  234          *      The location depends on V8086 mode.  If we are
  235          *      not in V8086 mode, then a trap into the kernel
  236          *      won`t save the v86 segments, so we leave room.
  237          */
  238 
  239         pcb_stack_top = (pcb->iss.efl & EFL_VM)
  240                         ? (int) (&pcb->iss + 1)
  241                         : (int) (&pcb->iss.v86_segs);
  242 
  243         if (tss == 0) {
  244             /*
  245              *  No per-thread IO permissions.
  246              *  Use standard kernel TSS.
  247              */
  248             if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
  249                 set_tr(KERNEL_TSS);
  250             curr_ktss(mycpu)->esp0 = pcb_stack_top;
  251         }
  252         else {
  253             /*
  254              * Set the IO permissions.  Use this thread`s TSS.
  255              */
  256             *gdt_desc_p(mycpu,USER_TSS)
  257                 = *(struct real_descriptor *)tss->iopb_desc;
  258             tss->tss.esp0 = pcb_stack_top;
  259             set_tr(USER_TSS);
  260             gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
  261         }
  262     }
  263 
  264     {
  265         register user_ldt_t     ldt = pcb->ims.ldt;
  266         /*
  267          * Set the thread`s LDT.
  268          */
  269         if (ldt == 0) {
  270             /*
  271              * Use system LDT.
  272              */
  273             set_ldt(KERNEL_LDT);
  274         }
  275         else {
  276             /*
  277              * Thread has its own LDT.
  278              */
  279             *gdt_desc_p(mycpu,USER_LDT) = ldt->desc;
  280             set_ldt(USER_LDT);
  281         }
  282     }
  283         /*
  284          * Load the floating-point context, if necessary.
  285          */
  286         fpu_load_context(pcb);
  287 
  288 }
  289 
  290 /*
  291  *      stack_handoff:
  292  *
  293  *      Move the current thread's kernel stack to the new thread.
  294  */
  295 
  296 void stack_handoff(old, new)
  297         register thread_t       old;
  298         register thread_t       new;
  299 {
  300         register int            mycpu = cpu_number();
  301         register vm_offset_t    stack;
  302 
  303         /*
  304          *      Save FP registers if in use.
  305          */
  306         fpu_save_context(old);
  307 
  308         /*
  309          *      Switch address maps if switching tasks.
  310          */
  311     {
  312         task_t old_task, new_task;
  313 
  314         if ((old_task = old->task) != (new_task = new->task)) {
  315                 PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
  316                                      old, mycpu);
  317                 PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
  318                                    new, mycpu);
  319         }
  320     }
  321 
  322         /*
  323          *      Load the rest of the user state for the new thread
  324          */
  325         switch_ktss(new->pcb);
  326 
  327         /*
  328          *      Switch to new thread
  329          */
  330         stack = current_stack();
  331         old->kernel_stack = 0;
  332         new->kernel_stack = stack;
  333         active_threads[mycpu] = new;
  334 
  335         /*
  336          *      Switch exception link to point to new
  337          *      user registers.
  338          */
  339 
  340         STACK_IEL(stack)->saved_state = &new->pcb->iss;
  341 
  342 }
  343 
  344 /*
  345  * Switch to the first thread on a CPU.
  346  */
  347 void load_context(new)
  348         register thread_t       new;
  349 {
  350         switch_ktss(new->pcb);
  351         Load_context(new);
  352 }
  353 
  354 /*
  355  * Switch to a new thread.
  356  * Save the old thread`s kernel state or continuation,
  357  * and return it.
  358  */
  359 thread_t switch_context(old, continuation, new)
  360         register thread_t       old;
  361         void (*continuation)();
  362         register thread_t       new;
  363 {
  364         /*
  365          *      Save FP registers if in use.
  366          */
  367         fpu_save_context(old);
  368 
  369         /*
  370          *      Switch address maps if switching tasks.
  371          */
  372     {
  373         task_t old_task, new_task;
  374         int     mycpu = cpu_number();
  375 
  376         if ((old_task = old->task) != (new_task = new->task)) {
  377                 PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
  378                                      old, mycpu);
  379                 PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
  380                                    new, mycpu);
  381         }
  382     }
  383 
  384         /*
  385          *      Load the rest of the user state for the new thread
  386          */
  387         switch_ktss(new->pcb);
  388 
  389         return Switch_context(old, continuation, new);
  390 }
  391 
  392 void pcb_module_init()
  393 {
  394         pcb_zone = zinit(sizeof(struct pcb),
  395                          THREAD_MAX * sizeof(struct pcb),
  396                          THREAD_CHUNK * sizeof(struct pcb),
  397                          FALSE, "i386 pcb state");
  398 
  399         fpu_module_init();
  400         iopb_init();
  401 }
  402 
  403 void pcb_init(thread)
  404         register thread_t       thread;
  405 {
  406         register pcb_t          pcb;
  407 
  408         pcb = (pcb_t) zalloc(pcb_zone);
  409         if (pcb == 0)
  410                 panic("pcb_init");
  411 
  412         counter(if (++c_threads_current > c_threads_max)
  413                         c_threads_max = c_threads_current);
  414 
  415         /*
  416          *      We can't let random values leak out to the user.
  417          */
  418         bzero((char *) pcb, sizeof *pcb);
  419         simple_lock_init(&pcb->lock);
  420 
  421         /*
  422          *      Guarantee that the bootstrapped thread will be in user
  423          *      mode.
  424          */
  425         pcb->iss.cs = USER_CS;
  426         pcb->iss.ss = USER_DS;
  427         pcb->iss.ds = USER_DS;
  428         pcb->iss.es = USER_DS;
  429         pcb->iss.fs = USER_DS;
  430         pcb->iss.gs = USER_DS;
  431         pcb->iss.efl = EFL_USER_SET;
  432 
  433         thread->pcb = pcb;
  434 }
  435 
  436 void pcb_terminate(thread)
  437         register thread_t       thread;
  438 {
  439         register pcb_t          pcb = thread->pcb;
  440 
  441         counter(if (--c_threads_current < c_threads_min)
  442                         c_threads_min = c_threads_current);
  443 
  444         if (pcb->ims.io_tss != 0)
  445                 iopb_destroy(pcb->ims.io_tss);
  446         if (pcb->ims.ifps != 0)
  447                 fp_free(pcb->ims.ifps);
  448         if (pcb->ims.ldt != 0)
  449                 user_ldt_free(pcb->ims.ldt);
  450         zfree(pcb_zone, (vm_offset_t) pcb);
  451         thread->pcb = 0;
  452 }
  453 
  454 /*
  455  *      pcb_collect:
  456  *
  457  *      Attempt to free excess pcb memory.
  458  */
  459 
  460 void pcb_collect(thread)
  461         thread_t thread;
  462 {
  463 }
  464 
  465 
  466 /*
  467  *      thread_setstatus:
  468  *
  469  *      Set the status of the specified thread.
  470  */
  471 
  472 kern_return_t thread_setstatus(thread, flavor, tstate, count)
  473         thread_t                thread;
  474         int                     flavor;
  475         thread_state_t          tstate;
  476         unsigned int            count;
  477 {
  478         switch (flavor) {
  479             case i386_THREAD_STATE:
  480             case i386_REGS_SEGS_STATE:
  481             {
  482                 register struct i386_thread_state       *state;
  483                 register struct i386_saved_state        *saved_state;
  484 
  485                 if (count < i386_THREAD_STATE_COUNT) {
  486                     return(KERN_INVALID_ARGUMENT);
  487                 }
  488 
  489                 if (flavor == i386_REGS_SEGS_STATE) {
  490                     /*
  491                      * Code and stack selectors must not be null,
  492                      * and must have user protection levels.
  493                      * Only the low 16 bits are valid.
  494                      */
  495                     state->cs &= 0xffff;
  496                     state->ss &= 0xffff;
  497                     state->ds &= 0xffff;
  498                     state->es &= 0xffff;
  499                     state->fs &= 0xffff;
  500                     state->gs &= 0xffff;
  501 
  502                     if (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U
  503                      || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U)
  504                         return KERN_INVALID_ARGUMENT;
  505                 }
  506 
  507                 state = (struct i386_thread_state *) tstate;
  508 
  509                 saved_state = USER_REGS(thread);
  510 
  511                 /*
  512                  * General registers
  513                  */
  514                 saved_state->edi = state->edi;
  515                 saved_state->esi = state->esi;
  516                 saved_state->ebp = state->ebp;
  517                 saved_state->uesp = state->uesp;
  518                 saved_state->ebx = state->ebx;
  519                 saved_state->edx = state->edx;
  520                 saved_state->ecx = state->ecx;
  521                 saved_state->eax = state->eax;
  522                 saved_state->eip = state->eip;
  523                 saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
  524                                     | EFL_USER_SET;
  525 
  526                 /*
  527                  * Segment registers.  Set differently in V8086 mode.
  528                  */
  529                 if (state->efl & EFL_VM) {
  530                     /*
  531                      * Set V8086 mode segment registers.
  532                      */
  533                     saved_state->cs = state->cs & 0xffff;
  534                     saved_state->ss = state->ss & 0xffff;
  535                     saved_state->v86_segs.v86_ds = state->ds & 0xffff;
  536                     saved_state->v86_segs.v86_es = state->es & 0xffff;
  537                     saved_state->v86_segs.v86_fs = state->fs & 0xffff;
  538                     saved_state->v86_segs.v86_gs = state->gs & 0xffff;
  539 
  540                     /*
  541                      * Zero protected mode segment registers.
  542                      */
  543                     saved_state->ds = 0;
  544                     saved_state->es = 0;
  545                     saved_state->fs = 0;
  546                     saved_state->gs = 0;
  547 
  548                     if (thread->pcb->ims.v86s.int_table) {
  549                         /*
  550                          * Hardware assist on.
  551                          */
  552                         thread->pcb->ims.v86s.flags =
  553                             state->efl & (EFL_TF | EFL_IF);
  554                     }
  555                 }
  556                 else if (flavor == i386_THREAD_STATE) {
  557                     /*
  558                      * 386 mode.  Set segment registers for flat
  559                      * 32-bit address space.
  560                      */
  561                     saved_state->cs = USER_CS;
  562                     saved_state->ss = USER_DS;
  563                     saved_state->ds = USER_DS;
  564                     saved_state->es = USER_DS;
  565                     saved_state->fs = USER_DS;
  566                     saved_state->gs = USER_DS;
  567                 }
  568                 else {
  569                     /*
  570                      * User setting segment registers.
  571                      * Code and stack selectors have already been
  572                      * checked.  Others will be reset by 'iret'
  573                      * if they are not valid.
  574                      */
  575                     saved_state->cs = state->cs;
  576                     saved_state->ss = state->ss;
  577                     saved_state->ds = state->ds;
  578                     saved_state->es = state->es;
  579                     saved_state->fs = state->fs;
  580                     saved_state->gs = state->gs;
  581                 }
  582                 break;
  583             }
  584 
  585             case i386_FLOAT_STATE: {
  586 
  587                 if (count < i386_FLOAT_STATE_COUNT)
  588                         return(KERN_INVALID_ARGUMENT);
  589 
  590                 return fpu_set_state(thread,
  591                                 (struct i386_float_state *) tstate);
  592             }
  593 
  594             /*
  595              * Temporary - replace by i386_io_map
  596              */
  597             case i386_ISA_PORT_MAP_STATE: {
  598                 register struct i386_isa_port_map_state *state;
  599                 register iopb_tss_t     tss;
  600 
  601                 if (count < i386_ISA_PORT_MAP_STATE_COUNT)
  602                         return(KERN_INVALID_ARGUMENT);
  603 
  604 #if 0
  605                 /*
  606                  *      If the thread has no ktss yet,
  607                  *      we must allocate one.
  608                  */
  609 
  610                 state = (struct i386_isa_port_map_state *) tstate;
  611                 tss = thread->pcb->ims.io_tss;
  612                 if (tss == 0) {
  613                         tss = iopb_create();
  614                         thread->pcb->ims.io_tss = tss;
  615                 }
  616 
  617                 bcopy((char *) state->pm,
  618                       (char *) tss->bitmap,
  619                       sizeof state->pm);
  620 #endif
  621                 break;
  622             }
  623 
  624             case i386_V86_ASSIST_STATE:
  625             {
  626                 register struct i386_v86_assist_state *state;
  627                 vm_offset_t     int_table;
  628                 int             int_count;
  629 
  630                 if (count < i386_V86_ASSIST_STATE_COUNT)
  631                     return KERN_INVALID_ARGUMENT;
  632 
  633                 state = (struct i386_v86_assist_state *) tstate;
  634                 int_table = state->int_table;
  635                 int_count = state->int_count;
  636 
  637                 if (int_table >= VM_MAX_ADDRESS ||
  638                     int_table +
  639                         int_count * sizeof(struct v86_interrupt_table)
  640                             > VM_MAX_ADDRESS)
  641                     return KERN_INVALID_ARGUMENT;
  642 
  643                 thread->pcb->ims.v86s.int_table = int_table;
  644                 thread->pcb->ims.v86s.int_count = int_count;
  645 
  646                 thread->pcb->ims.v86s.flags =
  647                         USER_REGS(thread)->efl & (EFL_TF | EFL_IF);
  648                 break;
  649             }
  650 
  651             default:
  652                 return(KERN_INVALID_ARGUMENT);
  653         }
  654 
  655         return(KERN_SUCCESS);
  656 }
  657 
  658 /*
  659  *      thread_getstatus:
  660  *
  661  *      Get the status of the specified thread.
  662  */
  663 
  664 kern_return_t thread_getstatus(thread, flavor, tstate, count)
  665         register thread_t       thread;
  666         int                     flavor;
  667         thread_state_t          tstate; /* pointer to OUT array */
  668         unsigned int            *count;         /* IN/OUT */
  669 {
  670         switch (flavor)  {
  671             case THREAD_STATE_FLAVOR_LIST:
  672                 if (*count < 4)
  673                     return (KERN_INVALID_ARGUMENT);
  674                 tstate[0] = i386_THREAD_STATE;
  675                 tstate[1] = i386_FLOAT_STATE;
  676                 tstate[2] = i386_ISA_PORT_MAP_STATE;
  677                 tstate[3] = i386_V86_ASSIST_STATE;
  678                 *count = 4;
  679                 break;
  680 
  681             case i386_THREAD_STATE:
  682             case i386_REGS_SEGS_STATE:
  683             {
  684                 register struct i386_thread_state       *state;
  685                 register struct i386_saved_state        *saved_state;
  686 
  687                 if (*count < i386_THREAD_STATE_COUNT)
  688                     return(KERN_INVALID_ARGUMENT);
  689 
  690                 state = (struct i386_thread_state *) tstate;
  691                 saved_state = USER_REGS(thread);
  692 
  693                 /*
  694                  * General registers.
  695                  */
  696                 state->edi = saved_state->edi;
  697                 state->esi = saved_state->esi;
  698                 state->ebp = saved_state->ebp;
  699                 state->ebx = saved_state->ebx;
  700                 state->edx = saved_state->edx;
  701                 state->ecx = saved_state->ecx;
  702                 state->eax = saved_state->eax;
  703                 state->eip = saved_state->eip;
  704                 state->efl = saved_state->efl;
  705                 state->uesp = saved_state->uesp;
  706 
  707                 state->cs = saved_state->cs;
  708                 state->ss = saved_state->ss;
  709                 if (saved_state->efl & EFL_VM) {
  710                     /*
  711                      * V8086 mode.
  712                      */
  713                     state->ds = saved_state->v86_segs.v86_ds & 0xffff;
  714                     state->es = saved_state->v86_segs.v86_es & 0xffff;
  715                     state->fs = saved_state->v86_segs.v86_fs & 0xffff;
  716                     state->gs = saved_state->v86_segs.v86_gs & 0xffff;
  717 
  718                     if (thread->pcb->ims.v86s.int_table) {
  719                         /*
  720                          * Hardware assist on
  721                          */
  722                         if ((thread->pcb->ims.v86s.flags &
  723                                         (EFL_IF|V86_IF_PENDING))
  724                                 == 0)
  725                             state->efl &= ~EFL_IF;
  726                     }
  727                 }
  728                 else {
  729                     /*
  730                      * 386 mode.
  731                      */
  732                     state->ds = saved_state->ds & 0xffff;
  733                     state->es = saved_state->es & 0xffff;
  734                     state->fs = saved_state->fs & 0xffff;
  735                     state->gs = saved_state->gs & 0xffff;
  736                 }
  737                 *count = i386_THREAD_STATE_COUNT;
  738                 break;
  739             }
  740 
  741             case i386_FLOAT_STATE: {
  742 
  743                 if (*count < i386_FLOAT_STATE_COUNT)
  744                         return(KERN_INVALID_ARGUMENT);
  745 
  746                 *count = i386_FLOAT_STATE_COUNT;
  747                 return fpu_get_state(thread,
  748                                 (struct i386_float_state *)tstate);
  749             }
  750 
  751             /*
  752              * Temporary - replace by i386_io_map
  753              */
  754             case i386_ISA_PORT_MAP_STATE: {
  755                 register struct i386_isa_port_map_state *state;
  756                 register iopb_tss_t tss;
  757 
  758                 if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
  759                         return(KERN_INVALID_ARGUMENT);
  760 
  761                 state = (struct i386_isa_port_map_state *) tstate;
  762                 tss = thread->pcb->ims.io_tss;
  763 
  764                 if (tss == 0) {
  765                     int i;
  766 
  767                     /*
  768                      *  The thread has no ktss, so no IO permissions.
  769                      */
  770 
  771                     for (i = 0; i < sizeof state->pm; i++)
  772                         state->pm[i] = 0xff;
  773                 } else {
  774                     /*
  775                      *  The thread has its own ktss.
  776                      */
  777 
  778                     bcopy((char *) tss->bitmap,
  779                           (char *) state->pm,
  780                           sizeof state->pm);
  781                 }
  782 
  783                 *count = i386_ISA_PORT_MAP_STATE_COUNT;
  784                 break;
  785             }
  786 
  787             case i386_V86_ASSIST_STATE:
  788             {
  789                 register struct i386_v86_assist_state *state;
  790 
  791                 if (*count < i386_V86_ASSIST_STATE_COUNT)
  792                     return KERN_INVALID_ARGUMENT;
  793 
  794                 state = (struct i386_v86_assist_state *) tstate;
  795                 state->int_table = thread->pcb->ims.v86s.int_table;
  796                 state->int_count = thread->pcb->ims.v86s.int_count;
  797 
  798                 *count = i386_V86_ASSIST_STATE_COUNT;
  799                 break;
  800             }
  801 
  802             default:
  803                 return(KERN_INVALID_ARGUMENT);
  804         }
  805 
  806         return(KERN_SUCCESS);
  807 }
  808 
  809 /*
  810  * Alter the thread`s state so that a following thread_exception_return
  811  * will make the thread return 'retval' from a syscall.
  812  */
  813 void
  814 thread_set_syscall_return(thread, retval)
  815         thread_t        thread;
  816         kern_return_t   retval;
  817 {
  818         thread->pcb->iss.eax = retval;
  819 }
  820 
  821 
  822 /*
  823  * Return prefered address of user stack.
  824  * Always returns low address.  If stack grows up,
  825  * the stack grows away from this address;
  826  * if stack grows down, the stack grows towards this
  827  * address.
  828  */
  829 vm_offset_t
  830 user_stack_low(stack_size)
  831         vm_size_t       stack_size;
  832 {
  833         return (VM_MAX_ADDRESS - stack_size);
  834 }
  835 
  836 /*
  837  * Allocate argument area and set registers for first user thread.
  838  */
  839 vm_offset_t
  840 set_user_regs(stack_base, stack_size, entry, arg_size)
  841         vm_offset_t     stack_base;     /* low address */
  842         vm_offset_t     stack_size;
  843         int             *entry;
  844         vm_size_t       arg_size;
  845 {
  846         vm_offset_t     arg_addr;
  847         register struct i386_saved_state *saved_state;
  848 
  849         arg_size = (arg_size + sizeof(int) - 1) & ~(sizeof(int)-1);
  850         arg_addr = stack_base + stack_size - arg_size;
  851 
  852         saved_state = USER_REGS(current_thread());
  853         saved_state->uesp = (int)arg_addr;
  854         saved_state->eip = entry[0];
  855 
  856         return (arg_addr);
  857 }

Cache object: bbb88f92cffc65d9c61a4f9196d40c84


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