📄 mpx386.s
字号:
#
! This file contains the assembler startup code for Minix and the 32-bit
! interrupt handlers. It cooperates with start.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.
! sections
.sect .text
begtext:
.sect .rom
begrom:
.sect .data
begdata:
.sect .bss
begbss:
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include "const.h"
#include "protect.h"
#include "sconst.h"
/* Selected 386 tss offsets. */
#define TSS3_S_SP0 4
! Exported functions
! 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
.define _restart
.define save
.define _divide_error
.define _single_step_exception
.define _nmi
.define _breakpoint_exception
.define _overflow
.define _bounds_check
.define _inval_opcode
.define _copr_not_available
.define _double_fault
.define _copr_seg_overrun
.define _inval_tss
.define _segment_not_present
.define _stack_exception
.define _general_protection
.define _page_fault
.define _copr_error
.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 _s_call
.define _p_s_call
.define _level0_call
! Imported functions.
.extern _cstart
.extern _main
.extern _exception
.extern _interrupt
.extern _sys_call
.extern _unhold
! 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 begbss
.define begdata
.define _sizes
! Imported variables.
.extern _gdt
.extern _code_base
.extern _data_base
.extern _held_head
.extern _k_reenter
.extern _pc_at
.extern _proc_ptr
.extern _ps_mca
.extern _tss
.extern _level0_func
.extern _mon_sp
.extern _mon_return
.extern _reboot_code
.sect .text
!*===========================================================================*
!* MINIX *
!*===========================================================================*
MINIX: ! this is the entry point for the MINIX kernel
jmp over_flags ! skip over the next few bytes
.data2 CLICK_SHIFT ! for the monitor: memory granularity
flags:
.data2 0x002D ! boot monitor flags:
! call in 386 mode, make stack,
! load high, will return
nop ! extra byte to sync up disassembler
over_flags:
! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds
! right. The ss descriptor still references the monitor data segment.)
movzx esp, sp ! monitor stack is a 16 bit stack
push ebp
mov ebp, esp
push esi
push edi
cmp 4(ebp), 0 ! nonzero if return possible
jz noret
inc (_mon_return)
noret: mov (_mon_sp), esp ! save stack pointer for later return
! Copy the monitor global descriptor table to the address space of kernel and
! switch over to it. Prot_init() can then update it with immediate effect.
sgdt (_gdt+GDT_SELECTOR) ! get the monitor gdtr
mov esi, (_gdt+GDT_SELECTOR+2) ! absolute address of GDT
mov ebx, _gdt ! address of kernel GDT
mov ecx, 8*8 ! copying eight descriptors
copygdt:
eseg movb al, (esi)
movb (ebx), al
inc esi
inc ebx
loop copygdt
mov eax, (_gdt+DS_SELECTOR+2) ! base of kernel data
and eax, 0x00FFFFFF ! only 24 bits
add eax, _gdt ! eax = vir2phys(gdt)
mov (_gdt+GDT_SELECTOR+2), eax ! set base of GDT
lgdt (_gdt+GDT_SELECTOR) ! switch over to kernel GDT
! Locate boot parameters, set up kernel segment registers and stack.
mov ebx, 8(ebp) ! boot parameters offset
mov edx, 12(ebp) ! boot parameters length
mov ax, ds ! kernel data
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, k_stktop ! set sp to point to the top of kernel stack
! Call C startup code to set up a proper environment to run main().
push edx
push ebx
push SS_SELECTOR
push MON_CS_SELECTOR
push DS_SELECTOR
push CS_SELECTOR
call _cstart ! cstart(cs, ds, mcs, mds, parmoff, parmlen)
add esp, 6*4
! Reload gdtr, idtr and the segment registers to global descriptor table set
! up by prot_init().
lgdt (_gdt+GDT_SELECTOR)
lidt (_gdt+IDT_SELECTOR)
jmpf CS_SELECTOR:csinit
csinit:
o16 mov ax, DS_SELECTOR
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
o16 mov ax, TSS_SELECTOR ! no other TSS is used
ltr ax
push 0 ! set flags to known good state
popf ! esp, clear nested task and int enable
jmp _main ! main()
!*===========================================================================*
!* interrupt handlers *
!* interrupt handlers for 386 32-bit protected mode *
!*===========================================================================*
!*===========================================================================*
!* 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 */;\
push irq /* irq */;\
call (_irq_table + 4*irq) /* eax = (*irq_table[irq])(irq) */;\
pop ecx ;\
cli /* disable interrupts */;\
test eax, eax /* 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
.align 16
_hwint00: ! Interrupt routine for irq 0 (the clock).
hwint_master(0)
.align 16
_hwint01: ! Interrupt routine for irq 1 (keyboard)
hwint_master(1)
.align 16
_hwint02: ! Interrupt routine for irq 2 (cascade!)
hwint_master(2)
.align 16
_hwint03: ! Interrupt routine for irq 3 (second serial)
hwint_master(3)
.align 16
_hwint04: ! Interrupt routine for irq 4 (first serial)
hwint_master(4)
.align 16
_hwint05: ! Interrupt routine for irq 5 (XT winchester)
hwint_master(5)
.align 16
_hwint06: ! Interrupt routine for irq 6 (floppy)
hwint_master(6)
.align 16
_hwint07: ! Interrupt routine for irq 7 (printer)
hwint_master(7)
!*===========================================================================*
!* hwint08 - 15 *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -