; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; kernel.asm; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; Forrest Yu, 2005; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%include "sconst.inc"; 导入函数extern cstartextern kernel_mainextern exception_handlerextern spurious_irqextern clock_handlerextern disp_strextern delayextern irq_tableextern page_fault_handlerextern divide_error_handler ;added by xw, 18/12/22extern disp_intextern scheduleextern switch_pde; 导入全局变量extern gdt_ptrextern idt_ptrextern p_proc_currentextern tssextern disp_posextern k_reenterextern sys_call_tableextern cr3_ready ;add by visual 2016年4月5日extern p_proc_currentextern p_proc_next ;added by xw, 18/4/26extern kernel_initial ;added by xw, 18/6/10bits 32[SECTION .data]clock_int_msg db "^", 0[SECTION .bss]StackSpace resb 2 * 1024StackTop: ; used only as irq-stack in minios. added by xw; added by xw, 18/6/15KernelStackSpace resb 2 * 1024KernelStackTop: ; used as stack of kernel itself; ~xw[section .text] ; 代码在此global _start ; 导出 _start;global restartglobal restart_initial ;Added by xw, 18/4/21global restart_restore ;Added by xw, 18/4/21;global save_contextglobal sched ;Added by xw, 18/4/21global sys_callglobal read_cr2 ;//add by visual 2016年5月9日global refresh_page_cache ; // add by visual 2016年5月12日global halt ;added by xw, 18/6/11global get_arg ;added by xw, 18/6/18global divide_errorglobal single_step_exceptionglobal nmiglobal breakpoint_exceptionglobal overflowglobal bounds_checkglobal inval_opcodeglobal copr_not_availableglobal double_faultglobal copr_seg_overrunglobal inval_tssglobal segment_not_presentglobal stack_exceptionglobal general_protectionglobal page_faultglobal copr_errorglobal hwint00global hwint01global hwint02global hwint03global hwint04global hwint05global hwint06global hwint07global hwint08global hwint09global hwint10global hwint11global hwint12global hwint13global hwint14global hwint15_start:; 此时内存看上去是这样的(更详细的内存情况在 LOADER.ASM 中有说明):; ┃ ┃; ┃ ... ┃; ┣━━━━━━━━━━━━━━━━━━┫; ┃■しかく■しかく■しかく■しかく■しかく■しかくPage Tables■しかく■しかく■しかく■しかく■しかく■しかく┃; ┃■しかく■しかく■しかく■しかく■しかく(大小由LOADER决定)■しかく■しかく■しかく■しかく┃ PageTblBase; 00101000h ┣━━━━━━━━━━━━━━━━━━┫; ┃■しかく■しかく■しかく■しかくPage Directory Table■しかく■しかく■しかく■しかく┃ PageDirBase = 1M; 00100000h ┣━━━━━━━━━━━━━━━━━━┫; ┃□しろいしかく□しろいしかく□しろいしかく□しろいしかく Hardware Reserved □しろいしかく□しろいしかく□しろいしかく□しろいしかく┃ B8000h ← gs; 9FC00h ┣━━━━━━━━━━━━━━━━━━┫; ┃■しかく■しかく■しかく■しかく■しかく■しかく■しかくLOADER.BIN■しかく■しかく■しかく■しかく■しかく■しかく┃ somewhere in LOADER ← esp; 90000h ┣━━━━━━━━━━━━━━━━━━┫; ┃■しかく■しかく■しかく■しかく■しかく■しかく■しかくKERNEL.BIN■しかく■しかく■しかく■しかく■しかく■しかく┃; 80000h ┣━━━━━━━━━━━━━━━━━━┫; ┃■しかく■しかく■しかく■しかく■しかく■しかく■しかく■しかくKERNEL■しかく■しかく■しかく■しかく■しかく■しかく■しかく┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr); 30000h ┣━━━━━━━━━━━━━━━━━━┫; ┋ ... ┋; ┋ ┋; 0h ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss;;; GDT 以及相应的描述符是这样的:;; Descriptors Selectors; ┏━━━━━━━━━━━━━━━━━━┓; ┃ Dummy Descriptor ┃; ┣━━━━━━━━━━━━━━━━━━┫; ┃ DESC_FLAT_C (0〜4G) ┃ 8h = cs; ┣━━━━━━━━━━━━━━━━━━┫; ┃ DESC_FLAT_RW (0〜4G) ┃ 10h = ds, es, fs, ss; ┣━━━━━━━━━━━━━━━━━━┫; ┃ DESC_VIDEO ┃ 1Bh = gs; ┗━━━━━━━━━━━━━━━━━━┛;; 注意! 在使用 C 代码的时候一定要保证 ds, es, ss 这几个段寄存器的值是一样的; 因为编译器有可能编译出使用它们的代码, 而编译器默认它们是一样的. 比如串拷贝操作会用到 ds 和 es.;;; 把 esp 从 LOADER 挪到 KERNEL; modified by xw, 18/6/15;mov esp, StackTop ; 堆栈在 bss 段中mov esp, KernelStackTop ; 堆栈在 bss 段中mov dword [disp_pos], 0sgdt [gdt_ptr] ; cstart() 中将会用到 gdt_ptrcall cstart ; 在此函数中改变了gdt_ptr,让它指向新的GDTlgdt [gdt_ptr] ; 使用新的GDTlidt [idt_ptr]jmp SELECTOR_KERNEL_CS:csinitcsinit: ; "这个跳转指令强制使用刚刚初始化的结构"——<<OS:D&I 2nd>> P90.;jmp 0x40:0;ud2xor eax, eaxmov ax, SELECTOR_TSSltr ax;stijmp kernel_main;hlt; 中断和异常 -- 硬件中断; ---------------------------------%macro hwint_master 1;call savecall save_int ;save registers and some other things. modified by xw, 17/12/11inc dword [k_reenter] ;If k_reenter isn't equal to 0, there is no switching to the irq-stack,;which is performed in save_int. Added by xw, 18/4/21in al, INT_M_CTLMASK ; `.or al, (1 << %1) ; | 屏蔽当前中断out INT_M_CTLMASK, al ; /mov al, EOI ; `. 置EOI位out INT_M_CTL, al ; /sti ; CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断push %1 ; `.call [irq_table + 4 * %1] ; | 中断处理程序pop ecx ; /; push eax ; ┓ add by visual 2016年4月5日; mov eax,[cr3_ready] ; ┣改变cr3; mov cr3,eax ; ┃; pop eax ; ┛clidec dword [k_reenter]in al, INT_M_CTLMASK ; `.and al, ~(1 << %1) ; | 恢复接受当前中断out INT_M_CTLMASK, al ; /ret%endmacroALIGN 16hwint00: ; Interrupt routine for irq 0 (the clock).hwint_master 0ALIGN 16hwint01: ; Interrupt routine for irq 1 (keyboard)hwint_master 1ALIGN 16hwint02: ; Interrupt routine for irq 2 (cascade!)hwint_master 2ALIGN 16hwint03: ; Interrupt routine for irq 3 (second serial)hwint_master 3ALIGN 16hwint04: ; Interrupt routine for irq 4 (first serial)hwint_master 4ALIGN 16hwint05: ; Interrupt routine for irq 5 (XT winchester)hwint_master 5ALIGN 16hwint06: ; Interrupt routine for irq 6 (floppy)hwint_master 6ALIGN 16hwint07: ; Interrupt routine for irq 7 (printer)hwint_master 7; ---------------------------------%macro hwint_slave 1;primary edition, commented by xw; push %1; call spurious_irq; add esp, 4; hlt;~xw;added by xw, 18/5/29call save_int ;save registers and some other things.inc dword [k_reenter] ;If k_reenter isn't equal to 0, there is no switching to the irq-stack,;which is performed in save_int. Added by xw, 18/4/21in al, INT_S_CTLMASK ; `.or al, (1 << (%1 - 8)) ; | 屏蔽当前中断out INT_S_CTLMASK, al ; /mov al, EOI ; `.out INT_M_CTL, al ; / 置EOI位(master)nop ; `.一定注意:slave和master都要置EOIout INT_S_CTL, al ; / 置EOI位(slave)sti ; CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断push %1 ; `.call [irq_table + 4 * %1] ; | 中断处理程序pop ecx ; /clidec dword [k_reenter]in al, INT_S_CTLMASK ; `.and al, ~(1 << (%1 - 8)) ; | 恢复接受当前中断out INT_S_CTLMASK, al ; /ret;~xw%endmacro; ---------------------------------ALIGN 16hwint08: ; Interrupt routine for irq 8 (realtime clock).hwint_slave 8ALIGN 16hwint09: ; Interrupt routine for irq 9 (irq 2 redirected)hwint_slave 9ALIGN 16hwint10: ; Interrupt routine for irq 10hwint_slave 10ALIGN 16hwint11: ; Interrupt routine for irq 11hwint_slave 11ALIGN 16hwint12: ; Interrupt routine for irq 12hwint_slave 12ALIGN 16hwint13: ; Interrupt routine for irq 13 (FPU exception)hwint_slave 13ALIGN 16hwint14: ; Interrupt routine for irq 14 (AT winchester)hwint_slave 14ALIGN 16hwint15: ; Interrupt routine for irq 15hwint_slave 15;commented by xw, 18/12/18;commented begin;; 中断和异常 -- 异常;divide_error:; push 0xFFFFFFFF ; no err code; push 0 ; vector_no = 0; jmp exception;single_step_exception:; push 0xFFFFFFFF ; no err code; push 1 ; vector_no = 1; jmp exception;nmi:; push 0xFFFFFFFF ; no err code; push 2 ; vector_no = 2; jmp exception;breakpoint_exception:; push 0xFFFFFFFF ; no err code; push 3 ; vector_no = 3; jmp exception;overflow:; push 0xFFFFFFFF ; no err code; push 4 ; vector_no = 4; jmp exception;bounds_check:; push 0xFFFFFFFF ; no err code; push 5 ; vector_no = 5; jmp exception;inval_opcode:; push 0xFFFFFFFF ; no err code; push 6 ; vector_no = 6; jmp exception;copr_not_available:; push 0xFFFFFFFF ; no err code; push 7 ; vector_no = 7; jmp exception;double_fault:; push 8 ; vector_no = 8; jmp exception;copr_seg_overrun:; push 0xFFFFFFFF ; no err code; push 9 ; vector_no = 9; jmp exception;inval_tss:; push 10 ; vector_no = A; jmp exception;segment_not_present:; push 11 ; vector_no = B; jmp exception;stack_exception:; push 12 ; vector_no = C; jmp exception;general_protection:; push 13 ; vector_no = D; jmp exception;page_fault:; ;page_fault_origin:; ;push 14 ; vector_no = E; ;jmp exception;; ;add by visual 2016年4月18日; pushad ; `.; push ds ; |; push es ; | 保存原寄存器值; push fs ; |; push gs ; /; mov dx, ss; mov ds, dx; mov es, dx; mov fs, dx ;value of fs and gs in user process is different to that in kernel; mov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20; mov gs, dx;; mov eax,[esp + RETADR - P_STACKBASE]; 把压入的错误码放进eax; mov ebx,[esp + EIPREG - P_STACKBASE]; 把压入的eip放进ebx; mov ecx,[esp + CSREG - P_STACKBASE]; 把压入的cs放进ecx; mov edx,[esp + EFLAGSREG - P_STACKBASE]; 把压入的eflags放进edx;; ;inc dword [k_reenter] ;k_reenter++; ;k_reenter only counts if irq reenters, xw, 18/4/20; ;cmp dword [k_reenter], 0 ;if(k_reenter ==0); ;jne .inkernel ;(k_reenter !=0); ;mov esp, StackTop ;deleted by xw, 17/12/11; ;.inkernel:; push edx ;压入eflags; push ecx ;压入cs; push ebx ;压入eip; push eax ;压入错误码; push 14 ; vector_no = E; ;jmp exception; ;call exception_handler edit by visual 2016年4月19日; call page_fault_handler;; add esp, 20 ;clear 5 arguments in stack, added by xw, 17/12/11; ;jmp restart; jmp restart_restore ;modified by xw, 17/12/11;;copr_error:; push 0xFFFFFFFF ; no err code; push 16 ; vector_no = 10h; jmp exception;;exception:; call exception_handler; add esp, 4*2 ; 让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS; hlt;commented by xw, 18/12/18;commented end; ====================================================================================; exception; ====================================================================================;restructured exception-handling procedure;added by xw, 18/12/18%macro exception_no_errcode 2push 0xFFFFFFFF ;no err codecall save_exception ;save registers and some other things.mov esi, esp ;esp points to pushed address of restart_exception at presentadd esi, 4 * 17 ;we use esi to help to fetch arguments of exception handler from the stack.;17 is calculated by: 4+8+retaddr+errcode+eip+cs+eflag=17mov eax, [esi] ;saved eflagspush eaxmov eax, [esi - 4] ;saved cspush eaxmov eax, [esi - 4 * 2] ;saved eippush eaxmov eax, [esi - 4 * 3] ;saved err codepush eaxpush %1 ;vector_nosticall %2cliadd esp, 4 * 5 ;clear arguments of exception handler in stackret ;returned to 'restart_exception' procedure%endmacro%macro exception_errcode 2call save_exception ;save registers and some other things.mov esi, esp ;esp points to pushed address of restart_exception at presentadd esi, 4 * 17 ;we use esi to help to fetch arguments of exception handler from the stack.;17 is calculated by: 4+8+retaddr+errcode+eip+cs+eflag=17mov eax, [esi] ;saved eflagspush eaxmov eax, [esi - 4] ;saved cspush eaxmov eax, [esi - 4 * 2] ;saved eippush eaxmov eax, [esi - 4 * 3] ;saved err codepush eaxpush %1 ;vector_nosticall %2cliadd esp, 4 * 5 ;clear arguments of exception handler in stackret ;returned to 'restart_exception' procedure%endmacrodivide_error: ; vector_no = 0; exception_no_errcode 0, exception_handlerexception_no_errcode 0, divide_error_handler ;added by xw, 18/12/22single_step_exception: ; vector_no = 1exception_no_errcode 1, exception_handlernmi: ; vector_no = 2exception_no_errcode 2, exception_handlerbreakpoint_exception: ; vector_no = 3exception_no_errcode 3, exception_handleroverflow: ; vector_no = 4exception_no_errcode 4, exception_handlerbounds_check: ; vector_no = 5exception_no_errcode 5, exception_handlerinval_opcode: ; vector_no = 6exception_no_errcode 6, exception_handlercopr_not_available: ; vector_no = 7exception_no_errcode 7, exception_handlerdouble_fault: ; vector_no = 8exception_errcode 8, exception_handlercopr_seg_overrun: ; vector_no = 9exception_no_errcode 9, exception_handlerinval_tss: ; vector_no = 10exception_errcode 10, exception_handlersegment_not_present: ; vector_no = 11exception_errcode 11, exception_handlerstack_exception: ; vector_no = 12exception_errcode 12, exception_handlergeneral_protection: ; vector_no = 13exception_errcode 13, exception_handlerpage_fault: ; vector_no = 14exception_errcode 14, page_fault_handlercopr_error: ; vector_no = 16exception_no_errcode 16, exception_handler;environment saving when an exception occurs;added by xw, 18/12/18save_exception:pushad ; `.push ds ; |push es ; | 保存原寄存器值push fs ; |push gs ; /mov dx, ssmov ds, dxmov es, dxmov fs, dx ;value of fs and gs in user process is different to that in kernelmov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20mov gs, dxmov esi, esppush restart_exceptionjmp [esi + RETADR - P_STACKBASE] ;the err code is in higher address than retaddr in stack, so there is;no need to modify the position jumped to, that is,;"jmp [esi + RETADR - 4 - P_STACKBASE]" is actually wrong.;added by xw, 18/12/18restart_exception:call schedpop gspop fspop espop dspopadadd esp, 4 * 2 ;clear retaddr and error code in stackiretd; ====================================================================================; save; ====================================================================================;modified by xw, 17/12/11;modified begin;save:; pushad ; `.; push ds ; |; push es ; | 保存原寄存器值; push fs ; |; push gs ; /; mov dx, ss; mov ds, dx; mov es, dx;; mov esi, esp ;esi = 进程表起始地址;; inc dword [k_reenter] ;k_reenter++;; cmp dword [k_reenter], 0 ;if(k_reenter ==0); jne .1 ;{; mov esp, StackTop ; mov esp, StackTop <--切换到内核栈; push restart ; push restart; jmp [esi + RETADR - P_STACKBASE]; return;;.1: ;} else { 已经在内核栈,不需要再切换; push restart_reenter ; push restart_reenter; jmp [esi + RETADR - P_STACKBASE]; return;; ;}save_int:pushad ; `.push ds ; |push es ; | 保存原寄存器值push fs ; |push gs ; /cmp dword [k_reenter], 0 ;Added by xw, 18/4/19jnz instackmov ebx, [p_proc_current] ;xwmov dword [ebx + ESP_SAVE_INT], esp ;xw save esp position in the kernel-stack of the process; or dword [ebx + SAVE_TYPE], 1 ;set 1st-bit of save_type, added by xw, 17/12/04mov dx, ssmov ds, dxmov es, dxmov fs, dx ;value of fs and gs in user process is different to that in kernelmov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20mov gs, dxmov esi, espmov esp, StackTop ;switches to the irq-stack from current process's kernel stackpush restart_int ;added by xw, 18/4/19jmp [esi + RETADR - P_STACKBASE]instack: ;already in the irq-stackpush restart_restore ;modified by xw, 18/4/19; jmp [esp + RETADR - P_STACKBASE]jmp [esp + 4 + RETADR - P_STACKBASE] ;modified by xw, 18/6/4save_syscall: ;can't modify EAX, for it contains syscall number;can't modify EBX, for it contains the syscall argumentpushad ; `.push ds ; |push es ; | 保存原寄存器值push fs ; |push gs ; /mov edx, [p_proc_current] ;xwmov dword [edx + ESP_SAVE_SYSCALL], esp ;xw save esp position in the kernel-stack of the process; or dword [edx + SAVE_TYPE], 4 ;set 3rd-bit of save_type, added by xw, 17/12/04mov dx, ssmov ds, dxmov es, dxmov fs, dx ;value of fs and gs in user process is different to that in kernelmov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20mov gs, dxmov esi, esp; inc dword [k_reenter]push restart_syscall ;modified by xw, 17/12/04; push judgejmp [esi + RETADR - P_STACKBASE];modified end; ====================================================================================; sched(process switch); ====================================================================================sched:;could be called by C function, you must save ebp, ebx, edi, esi,;for C function assumes that they stay unchanged. added by xw, 18/4/19;save_contextpushfdpushad ;modified by xw, 18/6/4cli; push ebp; push ebx; push edi; push esimov ebx, [p_proc_current]mov dword [ebx + ESP_SAVE_CONTEXT], esp ;save esp position in the kernel-stack of the process;schedulecall schedule ;schedule is a C function, save eax, ecx, edx if you want them to stay unchanged.;prepare to run new processmov ebx, [p_proc_next] ;added by xw, 18/4/26mov dword [p_proc_current], ebxcall renew_env ;renew process executing environment;restore_contextmov ebx, [p_proc_current]mov esp, [ebx + ESP_SAVE_CONTEXT] ;switch to a new kernel stack; pop esi; pop edi; pop ebx; pop ebp; sti ;popfd will be executed below, so sti is not needed. modified by xw, 18/12/27popadpopfdret; ====================================================================================; renew_env; ====================================================================================;renew process executing environment. Added by xw, 18/4/19renew_env:call switch_pde ;to change the global variable cr3_readymov eax,[cr3_ready] ;to switch the page directory tablemov cr3,eaxmov eax, [p_proc_current]lldt [eax + P_LDT_SEL] ;load LDTlea ebx, [eax + INIT_STACK_SIZE]mov dword [tss + TSS3_S_SP0], ebx ;renew esp0ret; ====================================================================================; judge; ====================================================================================;added by xw, 18/03/24;added begin;judge:; mov eax, [p_proc_current] ;get save_type; mov ebx, [eax + SAVE_TYPE]; test ebx, 1; jnz restart_int; test ebx, 2; jnz restart_context; test ebx, 4; jnz restart_syscall;added end; ====================================================================================; sys_call; ====================================================================================sys_call:;get syscall number from eax;syscall that's called gets its argument from pushed ebx;so we can't modify eax and ebx in save_syscallcall save_syscall ;save registers and some other things. modified by xw, 17/12/11stipush ebx ;push the argument the syscall needcall [sys_call_table + eax * 4] ;将参数压入堆栈后再调用函数 add by visual 2016年4月6日add esp, 4 ;clear the argument in the stack, modified by xw, 17/12/11climov edx, [p_proc_current]mov esi, [edx + ESP_SAVE_SYSCALL]mov [esi + EAXREG - P_STACKBASE], eax ;the return value of C function is in EAXret; ====================================================================================; restart; ====================================================================================;modified by xw;xw restart:;xw mov esp, [p_proc_ready];xw lldt [esp + P_LDT_SEL];xw lea eax, [esp + P_STACKTOP];xw mov dword [tss + TSS3_S_SP0], eaxrestart_int:mov eax, [p_proc_current]mov esp, [eax + ESP_SAVE_INT] ;switch back to the kernel stack from the irq-stackcmp dword [kernel_initial], 0 ;added by xw, 18/6/10jnz restart_restorecall sched ;save current process's context, invoke schedule(), and then;switch to the chosen process's kernel stack and restore it's context;added by xw, 18/4/19; call renew_envjmp restart_restorerestart_syscall:; sub ebx, 4 ;ebx gets its value from judge; mov dword [eax + SAVE_TYPE], ebx ;clear 3rd-bit of save_typemov eax, [p_proc_current]mov esp, [eax + ESP_SAVE_SYSCALL] ;xw restore esp positioncall sched ;added by xw, 18/4/26jmp restart_restore;xw restart_reenter:restart_restore:; dec dword [k_reenter]pop gspop fspop espop dspopadadd esp, 4iretd;restart_initial:; mov esp, [p_proc_current]; lldt [esp + P_LDT_SEL]; lea eax, [esp + INIT_STACK_SIZE]; mov dword [tss + TSS3_S_SP0], eax; mov esp, [esp + ESP_SAVE_INT] ;restore esp position; jmp restart_restore;to launch the first process in the os. added by xw, 18/4/19restart_initial:; mov eax, [p_proc_current]; lldt [eax + P_LDT_SEL]; lea ebx, [eax + INIT_STACK_SIZE]; mov dword [tss + TSS3_S_SP0], ebxcall renew_env ;renew process executing environmentmov eax, [p_proc_current]mov esp, [eax + ESP_SAVE_INT] ;restore esp positionjmp restart_restore; ====================================================================================; read_cr2 //add by visual 2016年5月9日; ====================================================================================read_cr2:mov eax,cr2ret; ====================================================================================; refresh_page_cache //add by visual 2016年5月12日; ====================================================================================refresh_page_cache:mov eax,cr3mov cr3,eaxret; ====================================================================================; halt //added by xw, 18/6/11; ====================================================================================halt:hlt; ====================================================================================; u32 get_arg(void *uesp, int order) //added by xw, 18/6/18; ====================================================================================; used to get the specified argument of the syscall from user space stack; @uesp: user space stack pointer; @order: which argument you want to get; @uesp+0: the number of args, @uesp+8: the first arg, @uesp+12: the second arg...get_arg:push ebpmov ebp, esppush esipush edimov esi, dword [ebp + 8] ;void *uespmov edi, dword [ebp + 12] ;int ordermov eax, dword [esi + edi * 4 + 4]pop edipop esipop ebpret
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。