home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / os / machsun3.tz / machsun3 / mk.kernel / sun3 / pcb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-15  |  12.6 KB  |  525 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1992 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.5  92/01/03  20:31:35  dbg
  30.  *     Add user_stack_low and set_user_regs for passing control to
  31.  *     bootstrap in user space.
  32.  *     [91/08/12            dbg]
  33.  * 
  34.  * Revision 2.4  91/07/31  18:13:55  dbg
  35.  *     Add stack_switching support.
  36.  *     [91/03/25            dbg]
  37.  * 
  38.  * Revision 2.3  91/03/16  14:58:56  rpd
  39.  *     Added continuation argument to stack_attach.
  40.  *     [91/03/14            rpd]
  41.  * 
  42.  * Revision 2.2  91/01/08  15:52:39  rpd
  43.  *     Added KEEP_STACKS support.
  44.  *     [91/01/06            rpd]
  45.  * 
  46.  *     Added empty frame on thread start for tracing.
  47.  *     [89/05/25            rwd]
  48.  * 
  49.  *     Converted for MACH kernel.
  50.  *     [88/11/03            dbg]
  51.  * 
  52.  * Revision 2.1  89/08/03  16:51:35  rwd
  53.  * Created.
  54.  * 
  55.  * Revision 2.5  88/08/25  18:20:11  mwyoung
  56.  *     Corrected include file references.
  57.  *     [88/08/22            mwyoung]
  58.  *     
  59.  *     Correct typo.
  60.  *     [88/08/12  13:30:43  mwyoung]
  61.  *     
  62.  *     Implement THREAD_STATE_FLAVOR_LIST flavor in thread_getstatus.
  63.  *     [88/08/11  18:49:15  mwyoung]
  64.  * 
  65.  * 17-Mar-88  David Golub (dbg) at Carnegie-Mellon University
  66.  *    Allow thread_setstatus to set the trace bits.
  67.  *
  68.  * 12-Feb-88  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  69.  *    Added call to fpa_save() in pcb_synch().
  70.  *    Changed to test FPA_USED bit in pcb_fpa_flags to see if
  71.  *    FPA is being used.
  72.  *
  73.  * 25-Jan-88  Robert Baron (rvb) at Carnegie-Mellon University
  74.  *    Rather than have "u" expand to current_thread()->u_address, have
  75.  *    it expand to the constant U_ADDRESS which is updated by load_context
  76.  *    when the thread changes.
  77.  *    Define load_context_data() to set U_ADDRESS.utask and U_ADDRESS.uthread.
  78.  *    And be sure to have initial_context call it.
  79.  *
  80.  * 21-Jan-88  David Golub (dbg) at Carnegie-Mellon University
  81.  *    Changed for new thread_status interface.
  82.  *
  83.  * 07-Jan-88  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  84.  *    Added call to fpa_fork_context() in thread_dup() to copy
  85.  *    FPA context from parent to child.
  86.  *    Created pcb_terminate().
  87.  *
  88.  * 17-Nov-87  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  89.  *    Changed FPIS_NULLSZ to FPIS_VERSNULL.
  90.  *
  91.  * 15-Dec-87  Richard Sanzi (sanzi) at Carnegie-Mellon University
  92.  *    Changed pcb parameter to pcb_init() to be the thread
  93.  *    (so that all functions in this module take consistent 
  94.  *    parameters).
  95.  *
  96.  * 17-Aug-87  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  97.  *    Changed thread_{set,get}status to return something of
  98.  *    type kern_return_t.
  99.  *
  100.  * 10-Jul-87  David Black (dlb) at Carnegie-Mellon University
  101.  *    Added pcb_synch() stub pending real implementation.
  102.  *
  103.  * 20-Apr-87  David Golub (dbg) at Carnegie-Mellon University
  104.  *    Added support for MACH.
  105.  *
  106.  * 23-Oct-86  David Golub (dbg) at Carnegie-Mellon University
  107.  *    Added thread_start for MACH option.
  108.  *
  109.  *  9-Aug-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  110.  *    Created.
  111.  *
  112.  */
  113.  
  114. #include <mach/kern_return.h>
  115. #include <mach/thread_status.h>
  116. #include <mach/vm_param.h>
  117.  
  118. #include <kern/counters.h>
  119. #include <kern/mach_param.h>
  120. #include <kern/thread.h>
  121. #include <kern/zalloc.h>
  122.  
  123. #include <machine/thread.h>
  124. #include <machine/psl.h>
  125. #include <machine/frame.h>
  126. #include <fpa.h>
  127. #if    NFPA >0
  128. #include <sundev/fpareg.h>
  129. #endif    NFPA >0
  130.  
  131. extern thread_t    Switch_context();
  132. extern void    Stack_handoff();
  133. extern void    Thread_continue();
  134.  
  135. zone_t    pcb_zone;
  136.  
  137. void stack_attach(thread, stack, continuation)
  138.     register thread_t    thread;
  139.     vm_offset_t        stack;
  140.     void            (*continuation)();
  141. {
  142.     counter(if (++c_stacks_current > c_stacks_max)
  143.             c_stacks_max = c_stacks_current);
  144.  
  145.     thread->kernel_stack = stack;
  146.  
  147.     /*
  148.      *    We want to run continuation, giving it as an argument
  149.      *    the return value from Load_context/Switch_context.
  150.      *    Thread_continue takes care of the mismatch between
  151.      *    the argument-passing/return-value conventions.
  152.      *    This function will not return normally,
  153.      *    so we don't have to worry about a return address.
  154.      */
  155.     STACK_MKS(stack)->pc = (int) (void (*)()) Thread_continue;
  156.     STACK_MKS(stack)->a2 = (int) continuation;
  157.     STACK_MKS(stack)->sp = (int) STACK_MKS(stack);
  158. }
  159.  
  160. vm_offset_t stack_detach(thread)
  161.     register thread_t    thread;
  162. {
  163.     register vm_offset_t    stack;
  164.  
  165.     counter(if (--c_stacks_current < c_stacks_min)
  166.             c_stacks_min = c_stacks_current);
  167.  
  168.     stack = thread->kernel_stack;
  169.     thread->kernel_stack = 0;
  170.     return stack;
  171. }
  172.  
  173. /*
  174.  *    stack_handoff:
  175.  *
  176.  *    Move the current thread's kernel stack to the new thread.
  177.  */
  178.  
  179. void stack_handoff(old, new)
  180.     register thread_t    old;
  181.     register thread_t    new;
  182. {
  183.  
  184.     fp_save(old);
  185.  
  186.     {
  187.     task_t    old_task, new_task;
  188.  
  189.     if ((old_task = old->task) != (new_task = new->task)) {
  190.         PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map), old, 0);
  191.         PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map), new, 0);
  192.     }
  193.     }
  194.  
  195.     active_threads[0] = new;
  196.     set_msp(new->pcb->user_regs);
  197.  
  198.     fp_restore(new);
  199. }
  200.  
  201. thread_t switch_context(old, continuation, new)
  202.     register thread_t    old;
  203.     void (*continuation)();
  204.     register thread_t    new;
  205. {
  206.  
  207.     fp_save(old);
  208.  
  209.     {
  210.     task_t    old_task, new_task;
  211.  
  212.     if ((old_task = old->task) != (new_task = new->task)) {
  213.         PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map), old, 0);
  214.         PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map), new, 0);
  215.     }
  216.     }
  217.  
  218.     return Switch_context(old, continuation, new);
  219. }
  220.  
  221. void pcb_module_init()
  222. {
  223.     pcb_zone = zinit(sizeof(struct pcb),
  224.              THREAD_MAX * sizeof(struct pcb),
  225.              THREAD_CHUNK * sizeof(struct pcb),
  226.              FALSE, "mc68020 pcb state");
  227. }
  228.  
  229.  
  230. extern thread_t    fp_threads[];
  231. extern short    fppstate;
  232.  
  233. void pcb_init(thread)
  234.     register thread_t    thread;
  235. {
  236.     register pcb_t        pcb;
  237.     register struct mc68020_saved_state *regs;
  238.  
  239.     pcb = (pcb_t) zalloc(pcb_zone);
  240.     thread->pcb = pcb;
  241.  
  242.     bzero((char *)pcb, sizeof(struct pcb));
  243.  
  244.     /*
  245.      * Set up the initial user register block.
  246.      * Put it at the very end of the user_state area,
  247.      * so that a full-size exception frame will still
  248.      * fit.
  249.      */
  250.     regs = ((struct mc68020_saved_state *)
  251.             &pcb->user_state[USER_STATE_SIZE]) - 1;
  252.     pcb->user_regs = regs;
  253.  
  254.     /*
  255.      *    Set up the initial user state.
  256.      */
  257.     regs->sr = SR_MASTER;    /* force to master stack on trap to kernel */
  258.     regs->stkfmt = 0;    /* short format stack frame */
  259.     regs->vector = 0;
  260. }
  261.  
  262. void pcb_terminate(thread)
  263.     register thread_t    thread;
  264. {
  265.     register pcb_t    pcb;
  266.  
  267.     pcb = thread->pcb;
  268.  
  269. #if    NFPA > 0
  270.     if (pcb->fpas)
  271.         fpaclose_thread(thread);
  272. #endif
  273.     zfree(pcb_zone, (vm_offset_t) pcb);
  274.     thread->pcb = 0;
  275. }
  276.  
  277. void pcb_collect(thread)
  278.     thread_t    thread;
  279. {
  280. }
  281.  
  282. /*
  283.  *    thread_setstatus:
  284.  *
  285.  *    Set the status of the specified thread.
  286.  */
  287.  
  288. kern_return_t thread_setstatus(thread, flavor, tstate, count)
  289.     thread_t        thread;
  290.     int            flavor;
  291.     thread_state_t        tstate;
  292.     unsigned int        count;
  293. {
  294.     register struct sun_thread_state    *state;
  295.     register pcb_t                pcb;
  296.     register struct mc68020_saved_state    *regs;
  297.  
  298.     if (flavor == SUN_THREAD_STATE_REGS) {
  299.         if (count < SUN_THREAD_STATE_REGS_COUNT) {
  300.         return(KERN_INVALID_ARGUMENT);
  301.         }
  302.         state = (struct sun_thread_state *) tstate;
  303.  
  304.         pcb = thread->pcb;
  305.         regs = pcb->user_regs;
  306.  
  307.         regs->d0 = state->d0;
  308.         regs->d1 = state->d1;
  309.         regs->d2 = state->d2;
  310.         regs->d3 = state->d3;
  311.         regs->d4 = state->d4;
  312.         regs->d5 = state->d5;
  313.         regs->d6 = state->d6;
  314.         regs->d7 = state->d7;
  315.  
  316.         regs->a0 = state->a0;
  317.         regs->a1 = state->a1;
  318.         regs->a2 = state->a2;
  319.         regs->a3 = state->a3;
  320.         regs->a4 = state->a4;
  321.         regs->a5 = state->a5;
  322.         regs->a6 = state->a6;
  323.         regs->sp = state->sp;
  324.  
  325.         if (regs->pc != state->pc)
  326.         pcb->discard_frame = TRUE;
  327.         regs->pc = state->pc;
  328.  
  329.         /*
  330.          *    Enforce user mode status register:
  331.          *    must have user mode, user stack, interrupt priority 0.
  332.          *    Force to master stack on trap to kernel mode.
  333.          *    User may set trace bits, but both trace bits cannot be
  334.          *    on (undefined).
  335.          */
  336.         regs->sr = state->sr & ~(SR_SMODE|SR_INTPRI) | SR_MASTER;
  337.         if ((regs->sr & (SR_T1|SR_T0)) == (SR_T1|SR_T0))
  338.         regs->sr &= ~SR_T0;
  339.  
  340.         if (fppstate > 0) {
  341.         /*
  342.          *    FP registers are in the pcb
  343.          */
  344.         if (state->fp.fps_flags == 0) {
  345.             /*
  346.              * no FP state
  347.              */
  348.             bzero((char *)&pcb->mc68881s,
  349.               sizeof(struct mc68881_state));
  350.         }
  351.         else {
  352.             /*
  353.              * FP state
  354.              */
  355.             if (pcb->mc68881s.fp_status.fps_flags == FPS_UNUSED) {
  356.             /* how do we make load_context load new FP
  357.                register values? */
  358.             }
  359.             pcb->mc68881s.fp_status = state->fp;
  360.         }
  361.         }
  362.         return(KERN_SUCCESS);
  363.     }
  364.     else if (flavor == SUN_THREAD_STATE_FPA) {
  365.         if (count < SUN_THREAD_STATE_FPA_COUNT)
  366.         return(KERN_INVALID_ARGUMENT);
  367.     
  368. #if    NFPA > 0
  369.         /*
  370.          *    Set this thread's FPA registers    XXX
  371.          */
  372. #else    NFPA > 0
  373.         return(KERN_FAILURE);        /* no FPA */
  374. #endif    NFPA > 0
  375.     }
  376.     else {
  377.         return(KERN_INVALID_ARGUMENT);
  378.     }
  379. }
  380.  
  381. /*
  382.  *    thread_getstatus:
  383.  *
  384.  *    Get the status of the specified thread.
  385.  */
  386.  
  387. kern_return_t thread_getstatus(thread, flavor, tstate, count)
  388.     register thread_t    thread;
  389.     int            flavor;
  390.     thread_state_t        tstate;    /* pointer to OUT array */
  391.     unsigned int        *count;        /* IN/OUT */
  392. {
  393.     register struct sun_thread_state    *state;
  394.     register pcb_t                pcb;
  395.     register struct mc68020_saved_state    *regs;
  396.  
  397.     switch (flavor) {
  398.         case THREAD_STATE_FLAVOR_LIST:
  399.         if (*count < 2)
  400.             return(KERN_INVALID_ARGUMENT);
  401.         tstate[0] = SUN_THREAD_STATE_REGS;
  402.         tstate[1] = SUN_THREAD_STATE_FPA;
  403.         *count = 2;
  404.         break;
  405.  
  406.         case SUN_THREAD_STATE_REGS:
  407.         if (*count < SUN_THREAD_STATE_REGS_COUNT) {
  408.             return(KERN_INVALID_ARGUMENT);
  409.         }
  410.  
  411.         state = (struct sun_thread_state *) tstate;
  412.  
  413.         pcb = thread->pcb;
  414.         regs = pcb->user_regs;
  415.  
  416.         state->d0 = regs->d0;
  417.         state->d1 = regs->d1;
  418.         state->d2 = regs->d2;
  419.         state->d3 = regs->d3;
  420.         state->d4 = regs->d4;
  421.         state->d5 = regs->d5;
  422.         state->d6 = regs->d6;
  423.         state->d7 = regs->d7;
  424.         state->a0 = regs->a0;
  425.         state->a1 = regs->a1;
  426.         state->a2 = regs->a2;
  427.         state->a3 = regs->a3;
  428.         state->a4 = regs->a4;
  429.         state->a5 = regs->a5;
  430.         state->a6 = regs->a6;
  431.         state->sp = regs->sp;
  432.  
  433.         state->pc = regs->pc;
  434.         state->sr = regs->sr;
  435.  
  436.         if (fppstate > 0) {
  437.             /*
  438.              *    Fp registers are in the PCB
  439.              */
  440.             pcb->mc68881s.fp_status.fps_flags =
  441.                 EXT_FPS_FLAGS(&pcb->mc68881s.fp_istate);
  442.             state->fp = pcb->mc68881s.fp_status;
  443.         }
  444.         else {
  445.             /*
  446.              *    FP not in use
  447.              */
  448.             bzero((char *)&state->fp, sizeof(state->fp));
  449.         }
  450.         *count = SUN_THREAD_STATE_REGS_COUNT;
  451.         break;
  452.             
  453.         case SUN_THREAD_STATE_FPA:
  454.         if (*count < SUN_THREAD_STATE_FPA_COUNT)
  455.             return(KERN_INVALID_ARGUMENT);
  456.     
  457. #if    NFPA > 0
  458.         /* XXX There probably should also be a runtime check
  459.          *     for FPA presence.
  460.          */
  461.         /*
  462.          *    Get this thread's FPA registers    XXX
  463.          */
  464.         *count = SUN_THREAD_STATE_FPA_COUNT;
  465. #else    NFPA > 0
  466.         return(KERN_FAILURE);        /* no FPA */
  467. #endif    NFPA > 0
  468.         break;
  469.  
  470.         default:
  471.         return(KERN_INVALID_ARGUMENT);
  472.     }
  473.     return(KERN_SUCCESS);
  474. }
  475.  
  476. /*
  477.  * Alter the thread`s state so that a following thread_exception_return
  478.  * will make the thread return 'retval' from a syscall.
  479.  */
  480. void
  481. thread_set_syscall_return(thread, retval)
  482.     thread_t    thread;
  483.     kern_return_t    retval;
  484. {
  485.     thread->pcb->user_regs->d0 = retval;
  486. }
  487.  
  488.  
  489. /*
  490.  * Return prefered address of user stack.
  491.  * Always returns low address.  If stack grows up,
  492.  * the stack grows away from this address;
  493.  * if stack grows down, the stack grows towards this
  494.  * address.
  495.  */
  496. vm_offset_t
  497. user_stack_low(stack_size)
  498.     vm_size_t    stack_size;
  499. {
  500.     return (VM_MAX_ADDRESS - stack_size);
  501. }
  502.  
  503. /*
  504.  * Allocate argument area and set registers for first user thread.
  505.  */
  506. vm_offset_t
  507. set_user_regs(stack_base, stack_size, entry, arg_size)
  508.     vm_offset_t    stack_base;    /* low address */
  509.     vm_offset_t    stack_size;
  510.     int        *entry;
  511.     vm_size_t    arg_size;
  512. {
  513.     vm_offset_t    arg_addr;
  514.     register struct mc68020_saved_state *saved_state;
  515.  
  516.     arg_size = (arg_size + sizeof(int) - 1) & ~(sizeof(int)-1);
  517.     arg_addr = stack_base + stack_size - arg_size;
  518.  
  519.     saved_state = current_thread()->pcb->user_regs;
  520.     saved_state->sp = (int)arg_addr;
  521.     saved_state->pc = entry[0];
  522.  
  523.     return (arg_addr);
  524. }
  525.