- ;By Marcus Xing
- ;/kernel/kernel.asm
- ;内核的入口,以及进行后续的一系列工作
- ;----------------------------------------------------------------------------EQU
- Selector_Kernel_Flat_RW equ 8 ;内核中GDT的FLAT_RW段选择子
- Selector_Kernel_Flat_C equ 16 ;内核中GDT的FLAT_C段选择子
- Selector_TSS equ 32 ;TSS的选择子
- Selector_Kernel_Flat_C_16 equ 126 * 8 ;内核中GDT中的FLAT的16位段的选择子
- Selector_Normal equ 127 * 8 ;Normal描述符的选择子
- LDT_Sel_Offset_Of_PCB equ 72 ;PCB中LDT选择子在PCB的偏移
- Stack_Frame_Top equ 72 ;PCB的寄存器的最高地址,从进程切换到中断处理
- ;程序时候esp应该指向[p_Next_PCB + Stack_Frame_Top]
- Save_Ret_Addr_Offset equ 48 ;Save函数的返回地址在PCB的偏移
- EAX_Offset equ 44 ;EAX寄存器在PCB的偏移
- EOI equ 20h
- TSS_ESP0_OFFSET equ 4 ;TSS结构ESP0字段的偏移
- ;-------------------------------------------------------------------------GLOBAL
- global _start ;默认入口点
- ;内中断处理函数导出
- global Divide_Error
- global Single_Step_Exception
- global NMI
- global Breakpoint_Exception
- global Overflow
- global Bounds_Check
- global Inval_Opcode
- global Copr_Not_Available
- global Double_Fault
- global Copr_Seg_Overrun
- global Inval_TSS
- global Segment_Not_Present
- global Stack_Exception
- global General_Protection
- global Page_Fault
- global Copr_Error
- ;外中断处理函数导出
- global hw_00
- global hw_01
- global hw_02
- global hw_03
- global hw_04
- global hw_05
- global hw_06
- global hw_07
- global hw_08
- global hw_09
- global hw_10
- global hw_11
- global hw_12
- global hw_13
- global hw_14
- global hw_15
- ;系统调用导出
- global System_Call
- global Prepare_To_Real_Mode
- ;-------------------------------------------------------------------------EXTERN
- ;各函数和变量的详细解释见include/proto.h和include/global.h
- ;FUNCTION
- extern Init_GDT
- extern Init_IDT
- extern GDT_Ptr
- extern IDT_Ptr
- extern Init_8259A
- extern Init_TSS
- extern Init_PCB
- extern Exception_Handler
- extern Hard_Int_Handler
- extern Disp_Str
- extern Delay
- extern Enable_IRQ
- extern Disable_IRQ
- extern Init_8253
- extern Init_Clock
- extern Init_Keyboard
- extern Init_All_TTY
- extern Memory_Copy
- ;VARIABLE
- extern d_Disp_Pos
- extern p_Next_PCB
- extern tss
- extern d_Flag_Reenter
- extern IRQ_Handler_Table
- extern System_Call_Handler_Table
- ;-------------------------------------------------------------------CODE_SEGMENT
- [section .text]
- [bits 32]
- _start:
- pop dword [d_Disp_Pos] ;把LOADER中的显示位置赋给KERNEL中的相应变量
- ;保存实模式下的IDTR和IMR的值
- sidt [b6_Old_IDTR_Value]
- in al,21h
- mov byte [b_Old_IMR],al
- ;复制保存下来的值到0:8000处
- push Data_Len
- push LABEL_DATA
- push 0x8000
- call Memory_Copy
- add esp,12
- ;复制1M下的实模式代码到0:9000h处
- push Code16_Len
- push LABEL_ALREADY_REAL_MODE
- push 0x9000
- call Memory_Copy
- add esp,12
- ;此时ds,es,fs,ss所指向的描述符还在LOADER,即GDT还在LOADER空间中
- call Init_GDT ;初始化GDT,但尚未切换
- call Init_8259A ;初始化8259a
- call Init_IDT ;初始化IDT,但尚未切换
- ;此时GDT已经移动到内核中,内容和LOADER中的GDT是一样的,所以选择子和一样
- lgdt [GDT_Ptr] ;加载入GDTR
- lidt [IDT_Ptr] ;加载入IDTR
- ;使用设置在内核的FLAT_C段
- jmp Selector_Kernel_Flat_C:_GO_ON
- _GO_ON:
- mov esp,Top_Of_Kernel_Stack ;堆栈顶指针也移动到内核空间中
- call Init_TSS ;初始化TSS
- call Init_PCB ;初始化PCB
- call Init_8253 ;初始化8253
- call Init_Clock ;初始化时钟中断
- call Init_Keyboard ;初始化键盘中断
- call Init_All_TTY ;初始化所有的TTY
- ;加载入tr
- mov ax,Selector_TSS
- ltr ax
- jmp Restart ;准备进入第一个进程
- Restart:
- mov esp,[p_Next_PCB] ;令esp指向将要执行的进程的PCB最低位置处,
- ;准备把PCB中的数据弹出
- ;加载进程的LDT选择子入ldtr
- lldt [esp + LDT_Sel_Offset_Of_PCB]
- ;设置TSS的ESP0字段为当前进程PCB的寄存器栈的最高地址
- lea eax,[esp + Stack_Frame_Top]
- mov [tss + TSS_ESP0_OFFSET],eax
- ;重入进入,不切换进程
- Reenter:
- dec dword [d_Flag_Reenter] ;重入标志变量自减1
- ;当前进程的PCB的各寄存值POP出去
- pop fs
- pop gs
- pop es
- pop ds
- popad
- add esp,4 ;跳过save_ret_addr
- ;正式进入第一个进程
- iretd
- ;-------------------------------------------------------------INNER_INT_HANDLERS
- ;有些内中断有错误码,有些没有,没有的就压入
- ;0ffffffffh值来代替,以此保持一致
- Divide_Error:
- push 0ffffffffh
- push 0
- jmp Exception
- Single_Step_Exception:
- push 0ffffffffh
- push 1
- jmp Exception
- NMI:
- push 0ffffffffh
- push 2
- jmp Exception
- Breakpoint_Exception:
- push 0ffffffffh
- push 3
- jmp Exception
- Overflow:
- push 0ffffffffh
- push 4
- jmp Exception
- Bounds_Check:
- push 0ffffffffh
- push 5
- jmp Exception
- Inval_Opcode:
- push 0ffffffffh
- push 6
- jmp Exception
- Copr_Not_Available:
- push 0ffffffffh
- push 7
- jmp Exception
- Double_Fault:
- push 8
- jmp Exception
- Copr_Seg_Overrun:
- push 0ffffffffh
- push 9
- jmp Exception
- Inval_TSS:
- push 10
- jmp Exception
- Segment_Not_Present:
- push 11
- jmp Exception
- Stack_Exception:
- push 12
- jmp Exception
- General_Protection:
- push 13
- jmp Exception
- Page_Fault:
- push 14
- jmp Exception
- Copr_Error:
- push 0ffffffffh
- push 16
- jmp Exception
- Exception:
- ;此时堆栈先后压入了eflags,cs,eip,error_code,int_vector
- call Exception_Handler ;此函数用C写成,统一处理
- add esp,8
- ;清掉了error_code,int_vector
- jmp $
- ; hlt
- ;---------------------------------------------------------------------------SAVE
- ;为下面的宏调用
- Save:
- ;此时esp为当前进程PCB的寄存器栈
- ;的最高地址处
- ;保存各寄存器到当前进程的PCB中
- pushad
- push ds
- push es
- push gs
- push fs
- ;RING0下设置GDT下的段寄存器,注意bx被改变
- mov bx,Selector_Kernel_Flat_RW
- mov ds,bx
- mov es,bx
- mov esi,esp ;esi指向当前进程的PCB的最低地址处
- ;重入标志自增1后如果不等于0,则是发生了重入
- inc dword [d_Flag_Reenter]
- cmp dword [d_Flag_Reenter],0
- jne .1
- mov esp,Top_Of_Kernel_Stack ;堆栈顶指针也移动到内核空间中
- push Restart ;压入Restart,进程切换
- jmp [esi + Save_Ret_Addr_Offset] ;回到调用Save的下一条语句
- ;中断重入就压入Reenter,此时已进入内核栈
- .1:
- push Reenter ;压入Reenter,进程不切换
- jmp [esi + Save_Ret_Addr_Offset] ;回到调用Save的下一条语句
- ;--------------------------------------------------------------HARD_INT_HANDLERS
- ;初始化外中断处理程序的宏
- %macro hw 1
- ;保存寄存器值到当前进程的PCB等功能
- ;调用后下一条指令的地址入PCB的save_ret_addr字段
- call Save
- ;通知8259A此次中断已结束
- mov al,EOI
- mov dx,20h
- out dx,al
- ;屏蔽当前向量号中断
- push %1
- call Enable_IRQ
- add esp,4
- sti ;发生中断时CPU自动关中断,这里人为打开
- ;如果是时钟中断
- ;进程调度,中断重入不重入都调度,在函数内判断
- ;跳入相应的处理函数处理
- mov eax,IRQ_Handler_Table
- push %1
- call [eax + (%1 * 4)] ;一个函数指针4字节
- add esp,4
- cli ;准备返回进程前关中断
- ;恢复当前向量号中断
- push %1
- call Enable_IRQ
- add esp,4
- ret ;准备返回
- %endmacro
- ;以下都是宏的扩展
- hw_00:
- hw 0 ;时钟中断处理程序
- hw_01:
- hw 1
- hw_02:
- hw 2
- hw_03:
- hw 3
- hw_04:
- hw 4
- hw_05:
- hw 5
- hw_06:
- hw 6
- hw_07:
- hw 7
- hw_08:
- hw 8
- hw_09:
- hw 9
- hw_10:
- hw 10
- hw_11:
- hw 11
- hw_12:
- hw 12
- hw_13:
- hw 13
- hw_14:
- hw 14
- hw_15:
- hw 15
- ;--------------------------------------------------------------------System_Call
- System_Call:
- ;由系统调用而进入到内核
- ;保存各寄存器的值到当前进程的PCB中
- call Save
- ;压入2个参数,对于0,1号系统调用没有意义,而2号就有意义
- push dword [p_Next_PCB]
- push edx
- push ecx
- push edi
- sti ;发生中断时CPU自动关中断,这里人为打开
- ;调用相应的处理函数
- call [System_Call_Handler_Table + eax * 4]
- add esp,16 ;平衡堆栈
- ;返回值写到PCB的EAX处,进程恢复时使用,对于1,2号系统调用没意义
- mov [esi + EAX_Offset],eax
- cli ;准备返回进程前关中断
- ret ;准备返回
- ;------------------------------------------------------------------STACK_SEGMENT
- ;内核栈
- [section .bss]
- [bits 32]
- LABEL_KERNEL_STACK_SPACE
- resb 2 * 1024
- Top_Of_Kernel_Stack
- ;-----------------------------------------------------------Prepare_To_Real_Mode
- [section .text]
- [bits 32]
- Prepare_To_Real_Mode:
- cli
- ;设置实模式下的8259A
- mov al,00010111b
- out 20h,al
- nop
- nop
- nop
- nop
- mov al,8h
- out 21h,al
- nop
- nop
- nop
- nop
- mov al,1h
- out 21h,al
- nop
- nop
- nop
- nop
- ;加载NORMAL描述符
- mov ax,Selector_Normal
- mov ds,ax
- mov es,ax
- mov gs,ax
- mov fs,ax
- mov ss,ax
- ;跳到16位代码段准备回到实模式
- jmp Selector_Kernel_Flat_C_16:LABEL_CODE16
- ;-------------------------------------------------------------------DATA_SEGMENT
- ;此段内容将被拷到0:8000h
- [section .data]
- [bits 32]
- LABEL_DATA:
- ;sz_Clock_Int_Msg db '^',0
- b6_Old_IDTR_Value times 6 db 0 ;存放实模式下的IDTR值
- b_Old_IMR db 0 ;存放实模式下的IMR值
- Data_Len equ $ - LABEL_DATA
- ;------------------------------------------------------------------------Code_16
- [section .text]
- [bits 16]
- LABEL_CODE16:
- ;关闭页表,切回实模式
- mov eax, cr0
- and eax, 7ffffffeh
- mov cr0, eax
- ;跳转到1M空间内执行,即交给下面这段代码执行
- jmp 0:9000h
- ;下面的代码将被拷到0:9000h处
- LABEL_ALREADY_REAL_MODE:
- ;初始化实模式下各段寄存器
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,7000h
- mov gs,ax
- mov fs,ax
- ;完成对8259A的设置
- mov al,[8006]
- out 21h,al
- lidt [8000]
- ;关闭 A20 地址线
- in al, 92h
- and al, 11111101b
- out 92h, al
- ;设置一系列寄存器的初始值
- mov ax,0aa55h
- xor bx,bx
- xor cx,cx
- xor dx,dx
- xor bp,bp
- mov sp,0ffd6h
- mov si,3258h
- mov di,0ffach
- ;重启
- jmp 0ffffh:0
- Code16_Len equ $ - LABEL_ALREADY_REAL_MODE