Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/sommerfeld_i386mp_1]: src/sys/arch/i386/i386 Revised (brutally hacked) c...



details:   https://anonhg.NetBSD.org/src/rev/a8e3bcc8ee1f
branches:  sommerfeld_i386mp_1
changeset: 482271:a8e3bcc8ee1f
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Fri Aug 18 14:01:11 2000 +0000

description:
Revised (brutally hacked) cpu_switch and idle which deals with the
multiprocessor case.  Works, but Really Ugly (code duplication, eliminates
APM hooks and idle-page-zero, switches to idle PCB even on uniprocessor).
In need of rewrite..

diffstat:

 sys/arch/i386/i386/locore.s  |  326 ++++++++++++++++++++++++++++++++++++++++++-
 sys/arch/i386/i386/mptramp.s |    5 +-
 2 files changed, 325 insertions(+), 6 deletions(-)

diffs (truncated from 384 to 300 lines):

diff -r e943ae26d70d -r a8e3bcc8ee1f sys/arch/i386/i386/locore.s
--- a/sys/arch/i386/i386/locore.s       Fri Aug 18 13:58:29 2000 +0000
+++ b/sys/arch/i386/i386/locore.s       Fri Aug 18 14:01:11 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: locore.s,v 1.215.2.10 2000/06/26 02:04:06 sommerfeld Exp $     */
+/*     $NetBSD: locore.s,v 1.215.2.11 2000/08/18 14:01:11 sommerfeld Exp $     */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -808,6 +808,9 @@
        call    _C_LABEL(main)
 
 NENTRY(proc_trampoline)
+#ifdef MULTIPROCESSOR
+       call    _C_LABEL(proc_trampoline_mp)
+#endif
        pushl   %ebx
        call    %esi
        addl    $4,%esp
@@ -1929,10 +1932,322 @@
        /* NOTREACHED */
 3:     .asciz  "remrunqueue"
 #endif /* DIAGNOSTIC */
-
-#if NAPM > 0
-       .globl _C_LABEL(apm_cpu_idle),_C_LABEL(apm_cpu_busy)
+       
+#ifdef DIAGNOSTIC
+NENTRY(switch_error)
+       pushl   $1f
+       call    _C_LABEL(panic)
+       /* NOTREACHED */
+1:     .asciz  "cpu_switch"
+#endif /* DIAGNOSTIC */
+
+/*
+ * void cpu_switch(struct proc *)
+ * Find a runnable process and switch to it.  Wait if necessary.  If the new
+ * process is the same as the old one, we short-circuit the context save and
+ * restore.
+ */
+ENTRY(cpu_switch)
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       pushl   CPL
+
+       GET_CURPROC(%esi,%ecx)
+
+       /*
+        * Clear curproc so that we don't accumulate system time while idle.
+        * This also insures that schedcpu() will move the old process to
+        * the correct queue if it happens to get called from the spllower()
+        * below and changes the priority.  (See corresponding comment in
+        * userret()).
+        */
+       CLEAR_CURPROC(%ecx)
+       /*
+        * First phase: find new process.
+        *
+        * Registers:
+        *   %eax - queue head, scratch, then zero
+        *   %ebx - queue number
+        *   %ecx - cached value of whichqs
+        *   %edx - next process in queue
+        *   %esi - old process
+        *   %edi - new process
+        */
+
+       /* Look for new process. */
+       cli                             # splhigh doesn't do a cli
+       movl    _C_LABEL(sched_whichqs),%ecx    # XXX MP
+
+       bsfl    %ecx,%ebx               # find a full q
+       jnz     switch_dequeue
+
+       /*
+        * idling:      save old context.
+        *
+        * Registers:
+        *   %eax, %ecx - scratch
+        *   %esi - old process, then old pcb
+        *   %edi - new process
+        */
+
+       movl    P_ADDR(%esi),%esi
+
+       /* Save segment registers. */
+       movl    %fs,%ax
+       movl    %gs,%cx
+       movl    %eax,PCB_FS(%esi)
+       movl    %ecx,PCB_GS(%esi)
+
+       /* Save stack pointers. */
+       movl    %esp,PCB_ESP(%esi)
+       movl    %ebp,PCB_EBP(%esi)
+
+       /* Find idle PCB for this CPU */
+#ifndef MULTIPROCESSOR
+       movl    $_C_LABEL(proc0),%ebx
+       movl    P_ADDR(%ebx),%esi
+#else
+       GET_CPUINFO(%ebx)
+       movl    CPU_INFO_IDLE_PCB(%ebx),%esi
+#endif
+       /* In case we fault... */
+       CLEAR_CURPROC(%ecx)
+
+       /* Restore the idle context (avoid interrupts) */
+       cli
+
+       /* Restore stack pointers. */
+       movl    PCB_ESP(%esi),%esp
+       movl    PCB_EBP(%esi),%ebp
+
+       /* Load TSS info. */
+       movl    _C_LABEL(gdt),%eax
+       movl    PCB_TSS_SEL(%esi),%edx
+
+       /* Switch address space. */
+       movl    PCB_CR3(%esi),%ecx
+       movl    %ecx,%cr3
+
+       /* Switch TSS. */
+       andl    $~0x0200,4-SEL_KPL(%eax,%edx,1)
+       ltr     %dx
+
+       /* We're always in the kernel, so we don't need the LDT. */
+
+       /* Clear segment registers; always null in proc0. */
+       xorl    %ecx,%ecx
+       movl    %cx,%fs
+       movl    %cx,%gs
+
+       /* Restore cr0 (including FPU state). */
+       movl    PCB_CR0(%esi),%ecx
+       movl    %ecx,%cr0
+
+       /* Record new pcb. */
+       SET_CURPCB(%esi, %ecx)
+
+       xorl    %esi,%esi
+#ifdef MULTIPROCESSOR  
+       pushl   $1
+       call    _C_LABEL(sched_unlock_idle)
+       popl    %eax
+#endif
+       /* Interrupts are okay again. */
+       sti
+       movl    $0,CPL                  # spl0()
+       call    _C_LABEL(Xspllower)     # process pending interrupts
+       jmp     idle_start
+idle_loop:     
+#ifdef MULTIPROCESSOR
+       pushl   $2
+       call    _C_LABEL(sched_unlock_idle)
+       popl    %eax
+#endif
+       sti
+       hlt
+NENTRY(mpidle)
+idle_start:    
+       cli
+#ifdef MULTIPROCESSOR
+       pushl   $3      
+       call    _C_LABEL(sched_lock_idle)
+       popl    %eax
 #endif
+       movl    _C_LABEL(sched_whichqs),%ecx
+       bsfl    %ecx,%ebx
+       jz      idle_loop
+
+switch_dequeue:                
+       leal    _C_LABEL(sched_qs)(,%ebx,8),%eax # select q
+
+       movl    P_FORW(%eax),%edi       # unlink from front of process q
+#ifdef DIAGNOSTIC
+       cmpl    %edi,%eax               # linked to self (i.e. nothing queued)?
+       je      _C_LABEL(switch_error)  # not possible
+#endif /* DIAGNOSTIC */
+       movl    P_FORW(%edi),%edx
+       movl    %edx,P_FORW(%eax)
+       movl    %eax,P_BACK(%edx)
+
+       cmpl    %edx,%eax               # q empty?
+       jne     3f
+
+       btrl    %ebx,%ecx               # yes, clear to indicate empty
+       movl    %ecx,_C_LABEL(sched_whichqs) # update q status
+
+3:     /* We just did it. */
+       CLEAR_RESCHED(%ecx)
+
+#ifdef DIAGNOSTIC
+       cmpl    %eax,P_WCHAN(%edi)      # Waiting for something?
+       jne     _C_LABEL(switch_error)  # Yes; shouldn't be queued.
+       cmpb    $SRUN,P_STAT(%edi)      # In run state?
+       jne     _C_LABEL(switch_error)  # No; shouldn't be queued.
+#endif /* DIAGNOSTIC */
+
+       /* Isolate process.  XXX Is this necessary? */
+       movl    %eax,P_BACK(%edi)
+
+       /* Record new process. */
+       movb    $SONPROC,P_STAT(%edi)   # p->p_stat = SONPROC
+       SET_CURPROC(%edi,%ecx)
+
+#ifdef MULTIPROCESSOR  
+       pushl   $4
+       call    _C_LABEL(sched_unlock_idle)
+       popl    %eax
+#endif
+       /* It's okay to take interrupts here. */
+       sti
+
+       /* Skip context switch if same process. */
+       cmpl    %edi,%esi
+       je      switch_return
+
+       /* If old process exited, don't bother. */
+       testl   %esi,%esi
+       jz      switch_exited
+
+       /*
+        * Second phase: save old context.
+        *
+        * Registers:
+        *   %eax, %ecx - scratch
+        *   %esi - old process, then old pcb
+        *   %edi - new process
+        */
+
+       movl    P_ADDR(%esi),%esi
+
+       /* Save segment registers. */
+       movl    %fs,%ax
+       movl    %gs,%cx
+       movl    %eax,PCB_FS(%esi)
+       movl    %ecx,PCB_GS(%esi)
+
+       /* Save stack pointers. */
+       movl    %esp,PCB_ESP(%esi)
+       movl    %ebp,PCB_EBP(%esi)
+
+switch_exited:
+       /*
+        * Third phase: restore saved context.
+        *
+        * Registers:
+        *   %eax, %ecx, %edx - scratch
+        *   %esi - new pcb
+        *   %edi - new process
+        */
+
+       /* No interrupts while loading new state. */
+       cli
+       movl    P_ADDR(%edi),%esi
+
+       /* Restore stack pointers. */
+       movl    PCB_ESP(%esi),%esp
+       movl    PCB_EBP(%esi),%ebp
+
+#if 0
+       /* Don't bother with the rest if switching to a system process. */
+       testl   $P_SYSTEM,P_FLAG(%edi)
+       jnz     switch_restored
+#endif
+
+       /* Load TSS info. */
+       movl    _C_LABEL(gdt),%eax
+       movl    PCB_TSS_SEL(%esi),%edx
+
+       /* Switch address space. */
+       movl    PCB_CR3(%esi),%ecx
+       movl    %ecx,%cr3
+
+       /* Switch TSS. Reset "task busy" flag before */
+       andl    $~0x0200,4(%eax,%edx, 1)
+       ltr     %dx
+
+#ifdef USER_LDT
+       /*
+        * Switch LDT.
+        *
+        * XXX
+        * Always do this, because the LDT could have been swapped into a
+        * different selector after a process exited.  (See gdt_compact().)
+        */
+       movl    PCB_LDT_SEL(%esi),%edx
+       lldt    %dx
+#endif /* USER_LDT */
+
+       /* Restore segment registers. */
+       movl    PCB_FS(%esi),%eax
+       movl    PCB_GS(%esi),%ecx
+       movl    %ax,%fs
+       movl    %cx,%gs
+
+switch_restored:
+       /* Restore cr0 (including FPU state). */



Home | Main Index | Thread Index | Old Index