++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
				src/kernel/mpx386.s	 	 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

05908	! Every transition to the kernel goes through this file.  Transitions are
05909	! caused by sending/receiving messages and by most interrupts.  (RS232
05910	! interrupts may be handled in the file "rs2.s" and then they rarely enter
05911	! the kernel.)
05912	
05913	! Transitions to the kernel may be nested.  The initial entry may be with a
05914	! system call, exception or hardware interrupt; reentries may only be made
05915	! by hardware interrupts.  The count of reentries is kept in "k_reenter".
05916	! It is important for deciding whether to switch to the kernel stack and
05917	! for protecting the message passing code in "proc.c".
05918	
05919	! For the message passing trap, most of the machine state is saved in the
05920	! proc table.  (Some of the registers need not be saved.)  Then the stack is
05921	! switched to "k_stack", and interrupts are reenabled.  Finally, the system
05922	! call handler (in C) is called.  When it returns, interrupts are disabled
05923	! again and the code falls into the restart routine, to finish off held-up
05924	! interrupts and run the process or task whose pointer is in "proc_ptr".
05925	
05926	! Hardware interrupt handlers do the same, except  (1) The entire state must
05927	! be saved.  (2) There are too many handlers to do this inline, so the save
05928	! routine is called.  A few cycles are saved by pushing the address of the
05929	! appropiate restart routine for a return later.  (3) A stack switch is
05930	! avoided when the stack is already switched.  (4) The (master) 8259 interrupt
05931	! controller is reenabled centrally in save().  (5) Each interrupt handler
05932	! masks its interrupt line using the 8259 before enabling (other unmasked)
05933	! interrupts, and unmasks it after servicing the interrupt.  This limits the
05934	! nest level to the number of lines and protects the handler from itself.
05935	
05936	! For communication with the boot monitor at startup time some constant
05937	! data are compiled into the beginning of the text segment. This facilitates 
05938	! reading the data at the start of the boot process, since only the first
05939	! sector of the file needs to be read.
05940	
05941	! Some data storage is also allocated at the end of this file. This data 
05942	! will be at the start of the data segment of the kernel and will be read
05943	! and modified by the boot monitor before the kernel starts.

06134	!*===========================================================================*
06135	!*                              interrupt handlers                           *
06136	!*              interrupt handlers for 386 32-bit protected mode             *
06137	!*===========================================================================*
06138	
06139	!*===========================================================================*
06140	!*                              hwint00 - 07                                 *
06141	!*===========================================================================*
06142	! Note this is a macro, it looks like a subroutine.
06143	#define hwint_master(irq)       \
06144	        call    save                    /* save interrupted process state */;\
06145	        inb     INT_CTLMASK                                                 ;\
06146	        orb     al, [1<<irq]                                                ;\
06147	        outb    INT_CTLMASK             /* disable the irq                */;\
06148	        movb    al, ENABLE                                                  ;\
06149	        outb    INT_CTL                 /* reenable master 8259           */;\
06150	        sti                             /* enable interrupts              */;\
06151	        push    irq                     /* irq                            */;\
06152	        call    (_irq_table + 4*irq)    /* eax = (*irq_table[irq])(irq)   */;\
06153	        pop     ecx                                                         ;\
06154	        cli                             /* disable interrupts             */;\
06155	        test    eax, eax                /* need to reenable irq?          */;\
06156	        jz      0f                                                          ;\
06157	        inb     INT_CTLMASK                                                 ;\
06158	        andb    al, ~[1<<irq]                                               ;\
06159	        outb    INT_CTLMASK             /* enable the irq                 */;\
06160	0:      ret                             /* restart (another) process      */

06195	!*===========================================================================*
06196	!*                              hwint08 - 15                                 *
06197	!*===========================================================================*
06198	! Note this is a macro, it looks like a subroutine.
06199	#define hwint_slave(irq)        \
06200	        call    save                    /* save interrupted process state */;\
06201	        inb     INT2_CTLMASK                                                ;\
06202	        orb     al, [1<<[irq-8]]                                            ;\
06203	        outb    INT2_CTLMASK            /* disable the irq                */;\
06204	        movb    al, ENABLE                                                  ;\
06205	        outb    INT_CTL                 /* reenable master 8259           */;\
06206	        jmp     .+2                     /* delay                          */;\
06207	        outb    INT2_CTL                /* reenable slave 8259            */;\
06208	        sti                             /* enable interrupts              */;\
06209	        push    irq                     /* irq                            */;\
06210	        call    (_irq_table + 4*irq)    /* eax = (*irq_table[irq])(irq)   */;\
06211	        pop     ecx                                                         ;\
06212	        cli                             /* disable interrupts             */;\
06213	        test    eax, eax                /* need to reenable irq?          */;\
06214	        jz      0f                                                          ;\
06215	        inb     INT2_CTLMASK                                                ;\
06216	        andb    al, ~[1<<[irq-8]]                                           ;\
06217	        outb    INT2_CTLMASK            /* enable the irq                 */;\
06218	0:      ret                             /* restart (another) process      */

06253	!*===========================================================================*
06254	!*                              save                                         *
06255	!*===========================================================================*
06256	! Save for protected mode.
06257	! This is much simpler than for 8086 mode, because the stack already points
06258	! into the process table, or has already been switched to the kernel stack.
06259	
06260	        .align  16
06261	save:
06262	        cld                     ! set direction flag to a known value
06263	        pushad                  ! save "general" registers
06264	    o16 push    ds              ! save ds
06265	    o16 push    es              ! save es
06266	    o16 push    fs              ! save fs
06267	    o16 push    gs              ! save gs
06268	        mov     dx, ss          ! ss is kernel data segment
06269	        mov     ds, dx          ! load rest of kernel segments
06270	        mov     es, dx          ! kernel does not use fs, gs
06271	        mov     eax, esp        ! prepare to return
06272	        incb    (_k_reenter)    ! from -1 if not reentering
06273	        jnz     set_restart1    ! stack is already kernel stack
06274	        mov     esp, k_stktop
06275	        push    _restart        ! build return address for int handler
06276	        xor     ebp, ebp        ! for stacktrace
06277	        jmp     RETADR-P_STACKBASE(eax)
06278	
06279	        .align  4
06280	set_restart1:
06281	        push    restart1
06282	        jmp     RETADR-P_STACKBASE(eax)

06284	!*===========================================================================*
06285	!*                              _s_call                                      *
06286	!*===========================================================================*
06287	        .align  16
06288	_s_call:
06289	_p_s_call:
06290	        cld                     ! set direction flag to a known value
06291	        sub     esp, 6*4        ! skip RETADR, eax, ecx, edx, ebx, est
06292	        push    ebp             ! stack already points into proc table
06293	        push    esi
06294	        push    edi
06295	    o16 push    ds
06296	    o16 push    es
06297	    o16 push    fs
06298	    o16 push    gs
06299	        mov     dx, ss
06300	        mov     ds, dx
06301	        mov     es, dx
06302	        incb    (_k_reenter)
06303	        mov     esi, esp        ! assumes P_STACKBASE == 0
06304	        mov     esp, k_stktop
06305	        xor     ebp, ebp        ! for stacktrace
06306	                                ! end of inline save
06307	        sti                     ! allow SWITCHER to be interrupted
06308	                                ! now set up parameters for sys_call()
06309	        push    ebx             ! pointer to user message
06310	        push    eax             ! src/dest
06311	        push    ecx             ! SEND/RECEIVE/BOTH
06312	        call    _sys_call       ! sys_call(function, src_dest, m_ptr)
06313	                                ! caller is now explicitly in proc_ptr
06314	        mov     AXREG(esi), eax ! sys_call MUST PRESERVE si
06315	        cli                     ! disable interrupts 
06316	
06317	! Fall into code to restart proc/task running.

06319	!*===========================================================================*
06320	!*                              restart                                      *
06321	!*===========================================================================*
06322	_restart:
06323	
06324	! Flush any held-up interrupts.
06325	! This reenables interrupts, so the current interrupt handler may reenter.
06326	! This does not matter, because the current handler is about to exit and no
06327	! other handlers can reenter since flushing is only done when k_reenter == 0.
06328	
06329	        cmp     (_held_head), 0 ! do fast test to usually avoid function call
06330	        jz      over_call_unhold
06331	        call    _unhold         ! this is rare so overhead acceptable
06332	over_call_unhold:
06333	        mov     esp, (_proc_ptr)        ! will assume P_STACKBASE == 0
06334	        lldt    P_LDT_SEL(esp)          ! enable segment descriptors for task
06335	        lea     eax, P_STACKTOP(esp)    ! arrange for next interrupt
06336	        mov     (_tss+TSS3_S_SP0), eax  ! to save state in process table
06337	restart1:
06338	        decb    (_k_reenter)
06339	    o16 pop     gs
06340	    o16 pop     fs
06341	    o16 pop     es
06342	    o16 pop     ds
06343	        popad
06344	        add     esp, 4          ! skip return adr
06345	        iretd                   ! continue process
