📄 mpx88.s
字号:
#
! This file contains the assembler startup code for Minix and the 16-bit
! interrupt handlers. It cooperates with cstart.c to set up a good
! environment for main().
! This file is part of the lowest layer of the MINIX kernel. The other part
! is "proc.c". The lowest layer does process switching and message handling.
! Every transition to the kernel goes through this file. Transitions are
! caused by sending/receiving messages and by most interrupts. (RS232
! interrupts may be handled in the file "rs2.s" and then they rarely enter
! the kernel.)
! Transitions to the kernel may be nested. The initial entry may be with a
! system call, exception or hardware interrupt; reentries may only be made
! by hardware interrupts. The count of reentries is kept in "k_reenter".
! It is important for deciding whether to switch to the kernel stack and
! for protecting the message passing code in "proc.c".
! For the message passing trap, most of the machine state is saved in the
! proc table. (Some of the registers need not be saved.) Then the stack is
! switched to "k_stack", and interrupts are reenabled. Finally, the system
! call handler (in C) is called. When it returns, interrupts are disabled
! again and the code falls into the restart routine, to finish off held-up
! interrupts and run the process or task whose pointer is in "proc_ptr".
! Hardware interrupt handlers do the same, except (1) The entire state must
! be saved. (2) There are too many handlers to do this inline, so the save
! routine is called. A few cycles are saved by pushing the address of the
! appropiate restart routine for a return later. (3) A stack switch is
! avoided when the stack is already switched. (4) The (master) 8259 interrupt
! controller is reenabled centrally in save(). (5) Each interrupt handler
! masks its interrupt line using the 8259 before enabling (other unmasked)
! interrupts, and unmasks it after servicing the interrupt. This limits the
! nest level to the number of lines and protects the handler from itself.
! For communication with the boot monitor at startup time some constant
! data are compiled into the beginning of the text segment. This facilitates
! reading the data at the start of the boot process, since only the first
! sector of the file needs to be read.
! Some data storage is also allocated at the end of this file. This data
! will be at the start of the data segment of the kernel and will be read
! and modified by the boot monitor before the kernel starts.
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include "const.h"
#include "sconst.h"
#include "protect.h"
! The external entry points into this file are:
! Note: in assembly language the .define statement applied to a function name
! is loosely equivalent to a prototype in C code -- it makes it possible to
! link to an entity declared in the assembly code but does not create
! the entity.
.define _idle_task ! executed when there is no work
.define _int00 ! handlers for traps and exceptions
.define _int01
.define _int02
.define _int03
.define _int04
.define _int05
.define _int06
.define _int07
.define _hwint00 ! handlers for hardware interrupts
.define _hwint01
.define _hwint02
.define _hwint03
.define _hwint04
.define _hwint05
.define _hwint06
.define _hwint07
.define _hwint08
.define _hwint09
.define _hwint10
.define _hwint11
.define _hwint12
.define _hwint13
.define _hwint14
.define _hwint15
.define _restart ! start running a task or process
.define save ! save the machine state in the proc table
.define _s_call ! process or task wants to send or receive a message
! Imported functions.
.extern _cstart
.extern _main
.extern _exception
.extern _interrupt
.extern _sys_call
.extern _unhold
.extern klib_init_prot
.extern real2prot
! Exported variables.
! Note: when used with a variable the .define does not reserve storage,
! it makes the name externally visible so it may be linked to.
.define kernel_ds
.define begbss
.define begdata
.define _sizes
! Imported variables.
.extern kernel_cs
.extern _gdt
.extern _code_base
.extern _data_base
.extern _held_head
.extern _k_reenter
.extern _pc_at
.extern _proc_ptr
.extern _protected_mode
.extern _ps_mca
.extern _irq_table
.text
!*===========================================================================*
!* MINIX *
!*===========================================================================*
MINIX: ! this is the entry point for the MINIX kernel
jmp over_kernel_ds ! skip over the next few bytes
.data2 CLICK_SHIFT ! for the monitor: memory granularity
kernel_ds:
.data2 0x0024 ! boot monitor flags: (later kernel DS)
! make stack, will return
over_kernel_ds:
! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds
! right. The ss register still references the monitor data segment.)
push bp
mov bp, sp
push si
push di
mov cx, 4(bp) ! monitor code segment
test cx, cx ! nonzero if return possible
jz noret
inc _mon_return
noret: mov _mon_ss, ss ! save stack location for later return
mov _mon_sp, sp
! Locate boot parameters, set up kernel segment registers and stack.
mov bx, 6(bp) ! boot parameters offset
mov dx, 8(bp) ! boot parameters length
mov ax, ds ! kernel data
mov es, ax
mov ss, ax
mov sp, #k_stktop ! set sp to point to the top of kernel stack
! Real mode needs to get kernel DS from the code segment. Protected mode
! needs CS in the jump back to real mode.
cseg mov kernel_cs, cs
cseg mov kernel_ds, ds
! Call C startup code to set up a proper environment to run main().
push dx
push bx
push _mon_ss
push cx
push ds
push cs
call _cstart ! cstart(cs, ds, mcs, mds, parmoff, parmlen)
add sp, #6*2
cmp _protected_mode, #0
jz nosw ! ok to switch to protected mode?
call klib_init_prot ! initialize klib functions for protected mode
call real2prot ! switch to protected mode
push #0 ! set flags to known good state
popf ! especially, clear nested task and int enable
nosw:
jmp _main ! main()
!*===========================================================================*
!* interrupt handlers *
!*===========================================================================*
!*===========================================================================*
!* hwint00 - 07 *
!*===========================================================================*
! Note this is a macro, it looks like a subroutine.
#define hwint_master(irq) \
call save /* save interrupted process state */;\
inb INT_CTLMASK ;\
orb al, *[1<<irq] ;\
outb INT_CTLMASK /* disable the irq */;\
movb al, *ENABLE ;\
outb INT_CTL /* reenable master 8259 */;\
sti /* enable interrupts */;\
mov ax, *irq ;\
push ax /* irq */;\
call @_irq_table + 2*irq /* ax = (*irq_table[irq])(irq) */;\
pop cx ;\
cli /* disable interrupts */;\
test ax, ax /* need to reenable irq? */;\
jz 0f ;\
inb INT_CTLMASK ;\
andb al, *~[1<<irq] ;\
outb INT_CTLMASK /* enable the irq */;\
0: ret /* restart (another) process */
! Each of these entry points is an expansion of the hwint_master macro
_hwint00: ! Interrupt routine for irq 0 (the clock).
hwint_master(0)
_hwint01: ! Interrupt routine for irq 1 (keyboard)
hwint_master(1)
_hwint02: ! Interrupt routine for irq 2 (cascade!)
hwint_master(2)
_hwint03: ! Interrupt routine for irq 3 (second serial)
hwint_master(3)
_hwint04: ! Interrupt routine for irq 4 (first serial)
hwint_master(4)
_hwint05: ! Interrupt routine for irq 5 (XT winchester)
hwint_master(5)
_hwint06: ! Interrupt routine for irq 6 (floppy)
hwint_master(6)
_hwint07: ! Interrupt routine for irq 7 (printer)
hwint_master(7)
!*===========================================================================*
!* hwint08 - 15 *
!*===========================================================================*
! Note this is a macro, it looks like a subroutine.
#define hwint_slave(irq) \
call save /* save interrupted process state */;\
inb INT2_CTLMASK ;\
orb al, *[1<<[irq-8]] ;\
outb INT2_CTLMASK /* disable the irq */;\
movb al, *ENABLE ;\
outb INT_CTL /* reenable master 8259 */;\
jmp .+2 /* delay */;\
outb INT2_CTL /* reenable slave 8259 */;\
sti /* enable interrupts */;\
mov ax, *irq ;\
push ax /* irq */;\
call @_irq_table + 2*irq /* eax = (*irq_table[irq])(irq) */;\
pop cx ;\
cli /* disable interrupts */;\
test ax, ax /* need to reenable irq? */;\
jz 0f ;\
inb INT2_CTLMASK ;\
andb al, *~[1<<[irq-8]] ;\
outb INT2_CTLMASK /* enable the irq */;\
0: ret /* restart (another) process */
! Each of these entry points is an expansion of the hwint_slave macro
_hwint08: ! Interrupt routine for irq 8 (realtime clock)
hwint_slave(8)
_hwint09: ! Interrupt routine for irq 9 (irq 2 redirected)
hwint_slave(9)
_hwint10: ! Interrupt routine for irq 10
hwint_slave(10)
_hwint11: ! Interrupt routine for irq 11
hwint_slave(11)
_hwint12: ! Interrupt routine for irq 12
hwint_slave(12)
_hwint13: ! Interrupt routine for irq 13 (FPU exception)
hwint_slave(13)
_hwint14: ! Interrupt routine for irq 14 (AT winchester)
hwint_slave(14)
_hwint15: ! Interrupt routine for irq 15
hwint_slave(15)
!*===========================================================================*
!* save *
!*===========================================================================*
save: ! save the machine state in the proc table.
! In protected mode a jump to p_save is patched over the following
! code during initialization.
cld ! set direction flag to a known value
push ds
push si
cseg mov ds,kernel_ds
incb _k_reenter ! from -1 if not reentering
jnz push_current_stack ! stack is already kernel stack
mov si,_proc_ptr
mov AXREG(si),ax
mov BXREG(si),bx
mov CXREG(si),cx
mov DXREG(si),dx
pop SIREG(si)
mov DIREG(si),di
mov BPREG(si),bp
mov ESREG(si),es
pop DSREG(si)
pop bx ! return adr
pop PCREG(si)
pop CSREG(si)
pop PSWREG(si)
mov SPREG(si),sp
mov SSREG(si),ss
mov dx,ds
mov ss,dx
mov sp,#k_stktop
mov ax,#_restart ! build return address for interrupt handler
push ax
stack_switched:
mov es,dx
jmp (bx)
push_current_stack:
push es
push bp
push di
push dx
push cx
push bx
push ax
mov bp,sp
mov bx,18(bp) ! get the return adr; it becomes junk on stack
mov ax,#restart1
push ax
mov dx,ss
mov ds,dx
jmp stack_switched
!*===========================================================================*
!* s_call *
!*===========================================================================*
! This is real mode version. Alternate (_p_s_call) will be used in
! protected mode
_s_call: ! System calls are vectored here.
! Do save routine inline for speed,
! but do not save ax, bx, cx, dx,
! since C does not require preservation,
! and ax returns the result code anyway.
! Regs bp, si, di get saved by sys_call as
! well, but it is impractical not to preserve
! them here, in case context gets switched.
! Some special-case code in pick_proc()
! could avoid this.
cld ! set direction flag to a known value
push ds
push si
cseg mov ds,kernel_ds
incb _k_reenter
mov si,_proc_ptr
pop SIREG(si)
mov DIREG(si),di
mov BPREG(si),bp
mov ESREG(si),es
pop DSREG(si)
pop PCREG(si)
pop CSREG(si)
pop PSWREG(si)
mov SPREG(si),sp
mov SSREG(si),ss
mov dx,ds
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -