作為一個作業系統,處理序是最為基本且重要的東西。不僅是一個處理序,應該是多個處理序。
然而,若要達到可控制處理序,就涉及到處理序和作業系統之間執行的轉換。
因為 CPU 只有一個,同一時刻要麼「客戶處理序」在執行,不然就是「作業系統」在執行。
因此,為達到處理序之目的,勢必要有一種控制權轉換機制,亦即「中斷」。
主要工作:設定 8259A 和建立 IDT
然而,若要達到可控制處理序,就涉及到處理序和作業系統之間執行的轉換。
因為 CPU 只有一個,同一時刻要麼「客戶處理序」在執行,不然就是「作業系統」在執行。
因此,為達到處理序之目的,勢必要有一種控制權轉換機制,亦即「中斷」。
主要工作:設定 8259A 和建立 IDT
程式碼
include/const.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ const.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_CONST_H_ #define _ORANGES_CONST_H_ /* EXTERN is defined as extern except in global.c */ #define EXTERN extern /* 函数类型 */ #define PUBLIC /* PUBLIC is the opposite of PRIVATE */ #define PRIVATE static /* PRIVATE x limits the scope of x */ /* GDT 和 IDT 中描述符的个数 */ #define GDT_SIZE 128 #define IDT_SIZE 256 /* 权限 */ #define PRIVILEGE_KRNL 0 #define PRIVILEGE_TASK 1 #define PRIVILEGE_USER 3 /* 8259A interrupt controller ports. */ #define INT_M_CTL 0x20 /* I/O port for interrupt controller <Master> */ #define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints <Master> */ #define INT_S_CTL 0xA0 /* I/O port for second interrupt controller<Slave> */ #define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints <Slave> */ #endif /* _ORANGES_CONST_H_ */
include/global.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ global.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* EXTERN is defined as extern except in global.c */ #ifdef GLOBAL_VARIABLES_HERE #undef EXTERN #define EXTERN #endif EXTERN int disp_pos; EXTERN u8 gdt_ptr[6]; /* 0~15:Limit 16~47:Base */ EXTERN DESCRIPTOR gdt[GDT_SIZE]; EXTERN u8 idt_ptr[6]; /* 0~15:Limit 16~47:Base */ EXTERN GATE idt[IDT_SIZE];
include/protect.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ protect.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_PROTECT_H_ #define _ORANGES_PROTECT_H_ /* 存儲段描述符/系統段描述符 */ typedef struct s_descriptor /* 共 8 個字節 */ { u16 limit_low; /* Limit */ u16 base_low; /* Base */ u8 base_mid; /* Base */ u8 attr1; /* P(1) DPL(2) DT(1) TYPE(4) */ u8 limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */ u8 base_high; /* Base */ }DESCRIPTOR; /* 門描述符 */ typedef struct s_gate { u16 offset_low; /* Offset Low */ u16 selector; /* Selector */ u8 dcount; /* 該字段只在調用門描述符中有效。如果在利用 調用門調用子程序時引起特權級的轉換和堆棧 的改變,需要將外層堆棧中的參數複製到內層 堆棧。該雙字計數字段就是用於說明這種情況 發生時,要複製的雙字參數的數量。*/ u8 attr; /* P(1) DPL(2) DT(1) TYPE(4) */ u16 offset_high; /* Offset High */ }GATE; /* GDT */ /* 描述符索引 */ #define INDEX_DUMMY 0 // ┓ #define INDEX_FLAT_C 1 // ┣ LOADER 裡面已經確定了的. #define INDEX_FLAT_RW 2 // ┃ #define INDEX_VIDEO 3 // ┛ /* 選擇子 */ #define SELECTOR_DUMMY 0 // ┓ #define SELECTOR_FLAT_C 0x08 // ┣ LOADER 裡面已經確定了的. #define SELECTOR_FLAT_RW 0x10 // ┃ #define SELECTOR_VIDEO (0x18+3) // ┛<-- RPL=3 #define SELECTOR_KERNEL_CS SELECTOR_FLAT_C #define SELECTOR_KERNEL_DS SELECTOR_FLAT_RW /* 描述符類型值說明 */ #define DA_32 0x4000 /* 32 位段 */ #define DA_LIMIT_4K 0x8000 /* 段界限粒度為 4K 字節 */ #define DA_DPL0 0x00 /* DPL = 0 */ #define DA_DPL1 0x20 /* DPL = 1 */ #define DA_DPL2 0x40 /* DPL = 2 */ #define DA_DPL3 0x60 /* DPL = 3 */ /* 存儲段描述符類型值說明 */ #define DA_DR 0x90 /* 存在的只讀數據段類型值 */ #define DA_DRW 0x92 /* 存在的可讀寫數據段屬性值 */ #define DA_DRWA 0x93 /* 存在的已訪問可讀寫數據段類型值 */ #define DA_C 0x98 /* 存在的只執行代碼段屬性值 */ #define DA_CR 0x9A /* 存在的可執行可讀代碼段屬性值 */ #define DA_CCO 0x9C /* 存在的只執行一致代碼段屬性值 */ #define DA_CCOR 0x9E /* 存在的可執行可讀一致代碼段屬性值 */ /* 系統段描述符類型值說明 */ #define DA_LDT 0x82 /* 局部描述符表段類型值 */ #define DA_TaskGate 0x85 /* 任務門類型值 */ #define DA_386TSS 0x89 /* 可用 386 任務狀態段類型值 */ #define DA_386CGate 0x8C /* 386 調用門類型值 */ #define DA_386IGate 0x8E /* 386 中斷門類型值 */ #define DA_386TGate 0x8F /* 386 陷阱門類型值 */ /* 中斷向量 */ #define INT_VECTOR_DIVIDE 0x0 #define INT_VECTOR_DEBUG 0x1 #define INT_VECTOR_NMI 0x2 #define INT_VECTOR_BREAKPOINT 0x3 #define INT_VECTOR_OVERFLOW 0x4 #define INT_VECTOR_BOUNDS 0x5 #define INT_VECTOR_INVAL_OP 0x6 #define INT_VECTOR_COPROC_NOT 0x7 #define INT_VECTOR_DOUBLE_FAULT 0x8 #define INT_VECTOR_COPROC_SEG 0x9 #define INT_VECTOR_INVAL_TSS 0xA #define INT_VECTOR_SEG_NOT 0xB #define INT_VECTOR_STACK_FAULT 0xC #define INT_VECTOR_PROTECTION 0xD #define INT_VECTOR_PAGE_FAULT 0xE #define INT_VECTOR_COPROC_ERR 0x10 /* 中斷向量 */ #define INT_VECTOR_IRQ0 0x20 #define INT_VECTOR_IRQ8 0x28 #endif /* _ORANGES_PROTECT_H_ */
include/proto.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ proto.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* klib.asm */ PUBLIC void out_byte(u16 port, u8 value); PUBLIC u8 in_byte(u16 port); PUBLIC void disp_str(char * info); PUBLIC void disp_color_str(char * info, int color); PUBLIC void init_prot(); PUBLIC void init_8259A();
include/string.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ string.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ PUBLIC void* memcpy(void* p_dst, void* p_src, int size);
include/type.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ type.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #ifndef _ORANGES_TYPE_H_ #define _ORANGES_TYPE_H_ typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; typedef void (*int_handler) (); #endif /* _ORANGES_TYPE_H_ */
kernel/global.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ global.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #define GLOBAL_VARIABLES_HERE #include "type.h" #include "const.h" #include "protect.h" #include "proto.h" #include "global.h"
kernel/i8259.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ i8259.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "proto.h" /*======================================================================* init_8259A *======================================================================*/ PUBLIC void init_8259A() { /* Master 8259, ICW1. */ out_byte(INT_M_CTL, 0x11); /* Slave 8259, ICW1. */ out_byte(INT_S_CTL, 0x11); /* Master 8259, ICW2. 設置 '主8259' 的中斷入口地址為 0x20. */ out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0); /* Slave 8259, ICW2. 設置 '從8259' 的中斷入口地址為 0x28 */ out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8); /* Master 8259, ICW3. IR2 對應 '從8259'. */ out_byte(INT_M_CTLMASK, 0x4); /* Slave 8259, ICW3. 對應 '主8259' 的 IR2. */ out_byte(INT_S_CTLMASK, 0x2); /* Master 8259, ICW4. */ out_byte(INT_M_CTLMASK, 0x1); /* Slave 8259, ICW4. */ out_byte(INT_S_CTLMASK, 0x1); /* Master 8259, OCW1. */ out_byte(INT_M_CTLMASK, 0xFD); /* Slave 8259, OCW1. */ out_byte(INT_S_CTLMASK, 0xFF); } /*======================================================================* spurious_irq *======================================================================*/ PUBLIC void spurious_irq(int irq) { disp_str("spurious_irq: "); disp_int(irq); disp_str("\n"); }
kernel/kernel.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; kernel.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SELECTOR_KERNEL_CS equ 8 ; 導入函數 extern cstart extern exception_handler extern spurious_irq ; 導入全局變量 extern gdt_ptr extern idt_ptr extern disp_pos [SECTION .bss] StackSpace resb 2 * 1024 StackTop: ; 堆疊頂 [section .text] ; 程式碼在此 global _start ; 導出 _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 hwint00 global hwint01 global hwint02 global hwint03 global hwint04 global hwint05 global hwint06 global hwint07 global hwint08 global hwint09 global hwint10 global hwint11 global hwint12 global hwint13 global hwint14 global 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 mov esp, StackTop ; 堆疊在 bss 段中 mov dword [disp_pos], 0 sgdt [gdt_ptr] ; cstart() 中將會用到 gdt_ptr call cstart ; 在此函數中改變了gdt_ptr,讓它指向新的GDT lgdt [gdt_ptr] ; 使用新的GDT lidt [idt_ptr] jmp SELECTOR_KERNEL_CS:csinit csinit: sti hlt ; 中斷和異常 -- 硬件中斷 ; --------------------------------- %macro hwint_master 1 push %1 call spurious_irq add esp, 4 hlt %endmacro ; --------------------------------- 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 ; --------------------------------- %macro hwint_slave 1 push %1 call spurious_irq add esp, 4 hlt %endmacro ; --------------------------------- ALIGN 16 hwint08: ; Interrupt routine for irq 8 (realtime clock). hwint_slave 8 ALIGN 16 hwint09: ; Interrupt routine for irq 9 (irq 2 redirected) hwint_slave 9 ALIGN 16 hwint10: ; Interrupt routine for irq 10 hwint_slave 10 ALIGN 16 hwint11: ; Interrupt routine for irq 11 hwint_slave 11 ALIGN 16 hwint12: ; Interrupt routine for irq 12 hwint_slave 12 ALIGN 16 hwint13: ; Interrupt routine for irq 13 (FPU exception) hwint_slave 13 ALIGN 16 hwint14: ; Interrupt routine for irq 14 (AT winchester) hwint_slave 14 ALIGN 16 hwint15: ; Interrupt routine for irq 15 hwint_slave 15 ; 中斷和異常 -- 異常 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: push 14 ; vector_no = E jmp exception 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
kernel/protect.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ protect.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "global.h" #include "proto.h" /* 本文件內函數聲明 */ PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege); /* 中斷處理函數 */ void divide_error(); void single_step_exception(); void nmi(); void breakpoint_exception(); void overflow(); void bounds_check(); void inval_opcode(); void copr_not_available(); void double_fault(); void copr_seg_overrun(); void inval_tss(); void segment_not_present(); void stack_exception(); void general_protection(); void page_fault(); void copr_error(); void hwint00(); void hwint01(); void hwint02(); void hwint03(); void hwint04(); void hwint05(); void hwint06(); void hwint07(); void hwint08(); void hwint09(); void hwint10(); void hwint11(); void hwint12(); void hwint13(); void hwint14(); void hwint15(); /*======================================================================* init_prot *======================================================================*/ PUBLIC void init_prot() { init_8259A(); // 全部初始化成中斷門(沒有陷阱門) init_idt_desc(INT_VECTOR_DIVIDE, DA_386IGate, divide_error, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_DEBUG, DA_386IGate, single_step_exception, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_NMI, DA_386IGate, nmi, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_BREAKPOINT, DA_386IGate, breakpoint_exception, PRIVILEGE_USER); init_idt_desc(INT_VECTOR_OVERFLOW, DA_386IGate, overflow, PRIVILEGE_USER); init_idt_desc(INT_VECTOR_BOUNDS, DA_386IGate, bounds_check, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_INVAL_OP, DA_386IGate, inval_opcode, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_NOT, DA_386IGate, copr_not_available, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_DOUBLE_FAULT, DA_386IGate, double_fault, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_SEG, DA_386IGate, copr_seg_overrun, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_INVAL_TSS, DA_386IGate, inval_tss, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_SEG_NOT, DA_386IGate, segment_not_present, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate, stack_exception, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_PROTECTION, DA_386IGate, general_protection, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_PAGE_FAULT, DA_386IGate, page_fault, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_COPROC_ERR, DA_386IGate, copr_error, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 0, DA_386IGate, hwint00, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 1, DA_386IGate, hwint01, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 2, DA_386IGate, hwint02, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 3, DA_386IGate, hwint03, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 4, DA_386IGate, hwint04, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 5, DA_386IGate, hwint05, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 6, DA_386IGate, hwint06, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ0 + 7, DA_386IGate, hwint07, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 0, DA_386IGate, hwint08, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 1, DA_386IGate, hwint09, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 2, DA_386IGate, hwint10, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 3, DA_386IGate, hwint11, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 4, DA_386IGate, hwint12, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 5, DA_386IGate, hwint13, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 6, DA_386IGate, hwint14, PRIVILEGE_KRNL); init_idt_desc(INT_VECTOR_IRQ8 + 7, DA_386IGate, hwint15, PRIVILEGE_KRNL); } /*======================================================================* init_idt_desc *----------------------------------------------------------------------* 初始化 386 中斷門 *======================================================================*/ PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege) { GATE * p_gate = &idt[vector]; u32 base = (u32)handler; p_gate->offset_low = base & 0xFFFF; p_gate->selector = SELECTOR_KERNEL_CS; p_gate->dcount = 0; p_gate->attr = desc_type | (privilege << 5); p_gate->offset_high = (base >> 16) & 0xFFFF; } /*======================================================================* exception_handler *----------------------------------------------------------------------* 異常處理 *======================================================================*/ PUBLIC void exception_handler(int vec_no,int err_code,int eip,int cs,int eflags) { int i; int text_color = 0x74; /* 灰底紅字 */ char * err_msg[] = {"#DE Divide Error", "#DB RESERVED", "— NMI Interrupt", "#BP Breakpoint", "#OF Overflow", "#BR BOUND Range Exceeded", "#UD Invalid Opcode (Undefined Opcode)", "#NM Device Not Available (No Math Coprocessor)", "#DF Double Fault", " Coprocessor Segment Overrun (reserved)", "#TS Invalid TSS", "#NP Segment Not Present", "#SS Stack-Segment Fault", "#GP General Protection", "#PF Page Fault", "— (Intel reserved. Do not use.)", "#MF x87 FPU Floating-Point Error (Math Fault)", "#AC Alignment Check", "#MC Machine Check", "#XF SIMD Floating-Point Exception" }; /* 通過打印空格的方式清空屏幕的前五行,並把 disp_pos 清零 */ disp_pos = 0; for(i=0;i<80*5;i++){ disp_str(" "); } disp_pos = 0; disp_color_str("Exception! --> ", text_color); disp_color_str(err_msg[vec_no], text_color); disp_color_str("\n\n", text_color); disp_color_str("EFLAGS:", text_color); disp_int(eflags); disp_color_str("CS:", text_color); disp_int(cs); disp_color_str("EIP:", text_color); disp_int(eip); if(err_code != 0xFFFFFFFF){ disp_color_str("Error code:", text_color); disp_int(err_code); } }
kernel/start.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ start.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "proto.h" #include "string.h" #include "global.h" /*======================================================================* cstart *======================================================================*/ PUBLIC void cstart() { disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "-----\"cstart\" begins-----\n"); /* 將 LOADER 中的 GDT 複製到新的 GDT 中 */ memcpy(&gdt, /* New GDT */ (void*)(*((u32*)(&gdt_ptr[2]))), /* Base of Old GDT */ *((u16*)(&gdt_ptr[0])) + 1 /* Limit of Old GDT */ ); /* gdt_ptr[6] 共 6 個字節:0~15:Limit 16~47:Base。用作 sgdt/lgdt 的參數。*/ u16* p_gdt_limit = (u16*)(&gdt_ptr[0]); u32* p_gdt_base = (u32*)(&gdt_ptr[2]); *p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1; *p_gdt_base = (u32)&gdt; /* idt_ptr[6] 共 6 個字節:0~15:Limit 16~47:Base。用作 sidt/lidt 的參數。*/ u16* p_idt_limit = (u16*)(&idt_ptr[0]); u32* p_idt_base = (u32*)(&idt_ptr[2]); *p_idt_limit = IDT_SIZE * sizeof(GATE) - 1; *p_idt_base = (u32)&idt; init_prot(); disp_str("-----\"cstart\" ends-----\n"); }
lib/kliba.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; klib.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; 導入全局變量 extern disp_pos [SECTION .text] ; 導出函數 global disp_str global disp_color_str global out_byte global in_byte ; ======================================================================== ; void disp_str(char * pszInfo); ; ======================================================================== disp_str: push ebp mov ebp, esp mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, 0Fh .1: lodsb test al, al jz .2 cmp al, 0Ah ; 是ENTER嗎? jnz .3 push eax mov eax, edi mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret ; ======================================================================== ; void disp_color_str(char * info, int color); ; ======================================================================== disp_color_str: push ebp mov ebp, esp mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, [ebp + 12] ; color .1: lodsb test al, al jz .2 cmp al, 0Ah ; 是ENTER嗎? jnz .3 push eax mov eax, edi mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret ; ======================================================================== ; void out_byte(u16 port, u8 value); ; ======================================================================== out_byte: mov edx, [esp + 4] ; port mov al, [esp + 4 + 4] ; value out dx, al nop ; 一點延遲 nop ret ; ======================================================================== ; u8 in_byte(u16 port); ; ======================================================================== in_byte: mov edx, [esp + 4] ; port xor eax, eax in al, dx nop ; 一點延遲 nop ret
lib/klib.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ klib.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "const.h" #include "protect.h" #include "proto.h" #include "string.h" #include "global.h" /*======================================================================* itoa *======================================================================*/ /* 數字前面的 0 不被顯示出來, 比如 0000B800 被顯示成 B800 */ PUBLIC char * itoa(char * str, int num) { char * p = str; char ch; int i; int flag = 0; *p++ = '0'; *p++ = 'x'; if(num == 0){ *p++ = '0'; } else{ for(i=28;i>=0;i-=4){ ch = (num >> i) & 0xF; if(flag || (ch > 0)){ flag = 1; ch += '0'; if(ch > '9'){ ch += 7; } *p++ = ch; } } } *p = 0; return str; } /*======================================================================* disp_int *======================================================================*/ PUBLIC void disp_int(int input) { char output[16]; itoa(output, input); disp_str(output); }
lib/string.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; string.asm ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Forrest Yu, 2005 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ [SECTION .text] ; 導出函數 global memcpy ; ------------------------------------------------------------------------ ; void* memcpy(void* es:pDest, void* ds:pSrc, int iSize); ; ------------------------------------------------------------------------ memcpy: push ebp mov ebp, esp push esi push edi push ecx mov edi, [ebp + 8] ; Destination mov esi, [ebp + 12] ; Source mov ecx, [ebp + 16] ; Counter .1: cmp ecx, 0 ; 判斷計數器 jz .2 ; 計數器為零時跳出 mov al, [ds:esi] ; ┓ inc esi ; ┃ ; ┣ 逐字元移動 mov byte [es:edi], al ; ┃ inc edi ; ┛ dec ecx ; 計數器減一 jmp .1 ; 循環 .2: mov eax, [ebp + 8] ; 返回值 pop ecx pop edi pop esi mov esp, ebp pop ebp ret ; 函數結束,返回 ; memcpy 結束-------------------------------------------------------------
Makefile
######################### # Makefile for Orange'S # ######################### # Entry point of Orange'S # It must have the same value with 'KernelEntryPointPhyAddr' in load.inc! ENTRYPOINT = 0x30400 # Offset of entry point in kernel file # It depends on ENTRYPOINT ENTRYOFFSET = 0x400 # Programs, flags, etc. ASM = nasm DASM = ndisasm CC = gcc LD = ld ASMBFLAGS = -I boot/include/ ASMKFLAGS = -I include/ -f elf CFLAGS = -I include/ -m32 -c -fno-builtin -fno-stack-protector LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT) DASMFLAGS = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET) # This Program ORANGESBOOT = boot/boot.bin boot/loader.bin ORANGESKERNEL = kernel.bin OBJS = kernel/kernel.o kernel/start.o kernel/i8259.o kernel/global.o kernel/protect.o lib/klib.o lib/kliba.o lib/string.o DASMOUTPUT = kernel.bin.asm # All Phony Targets .PHONY : everything final image clean realclean disasm all buildimg # Default starting position everything : $(ORANGESBOOT) $(ORANGESKERNEL) all : realclean everything final : all clean image : final buildimg clean : rm -f $(OBJS) realclean : rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL) disasm : $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT) # We assume that "a.img" exists in current folder buildimg : mkdir tmp dd if=boot/boot.bin of=a.img bs=512 count=1 conv=notrunc sleep 1 sudo mount -o loop a.img tmp sleep 1 sudo cp -fv boot/loader.bin tmp sudo cp -fv kernel.bin tmp sleep 1 sudo umount tmp sleep 1 rmdir tmp boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc $(ASM) $(ASMBFLAGS) -o $@ $< boot/loader.bin : boot/loader.asm boot/include/load.inc \ boot/include/fat12hdr.inc boot/include/pm.inc $(ASM) $(ASMBFLAGS) -o $@ $< $(ORANGESKERNEL) : $(OBJS) $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS) kernel/kernel.o : kernel/kernel.asm $(ASM) $(ASMKFLAGS) -o $@ $< kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h \ include/proto.h include/string.h $(CC) $(CFLAGS) -o $@ $< kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \ include/proto.h $(CC) $(CFLAGS) -o $@ $< kernel/global.o : kernel/global.c $(CC) $(CFLAGS) -o $@ $< kernel/protect.o : kernel/protect.c $(CC) $(CFLAGS) -o $@ $< lib/klib.o : lib/klib.c $(CC) $(CFLAGS) -o $@ $< lib/kliba.o : lib/kliba.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/string.o : lib/string.asm $(ASM) $(ASMKFLAGS) -o $@ $<
留言
張貼留言