/kernel/kernel.asm

;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 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 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 sz_Clock_Int_Msg ;call Disp_Str ;add esp,4 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自动关中断,这里人为打开 ;调用延时函数 ;push 1 ;call Delay ;add esp,4 ;如果是时钟中断 ;进程调度,中断重入不重入都调度,在函数内判断 ;跳入相应的处理函数处理 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 ;压入3个参数,对于0,1号系统调用没有意义,而2号就有意义 push dword [p_Next_PCB] push ecx push edx sti ;发生中断时CPU自动关中断,这里人为打开 ;调用相应的处理函数 call [System_Call_Handler_Table + eax * 4] add esp,12 ;返回值写到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

你可能感兴趣的:(工作,exception,table,System,扩展,keyboard)