参考
https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程
主要代码:
kmain.c
#include "kernel.h" #include "screen.h" #include "global.h" void (* const InitInterrupt)() = NULL; void (* const EnableTimer)() = NULL; void (* const SendEOI)(uint port) = NULL; volatile Task* gCTaskAddr = NULL; Task p = {0}; Task t = {0}; TSS gTSS = {0}; void InitTask(Task* pt, void(*entry)()) { pt->rv.cs = LDT_CODE32_SELECTOR; pt->rv.gs = LDT_VIDEO_SELECTOR; pt->rv.ds = LDT_DATA32_SELECTOR; pt->rv.es = LDT_DATA32_SELECTOR; pt->rv.fs = LDT_DATA32_SELECTOR; pt->rv.ss = LDT_DATA32_SELECTOR; pt->rv.esp = (uint)pt->stack + sizeof(pt->stack); pt->rv.eip = (uint)entry; pt->rv.eflags = 0x3202; gTSS.ss0 = GDT_DATA32_FLAT_SELECTOR; gTSS.esp0 = (uint)&pt->rv + sizeof(pt->rv); gTSS.iomb = sizeof(TSS); SetDescValue(pt->ldt + LDT_VIDEO_INDEX, 0xB8000, 0x07FFF, DA_DRWA + DA_32 + DA_DPL3); SetDescValue(pt->ldt + LDT_CODE32_INDEX, 0x00, 0xFFFFF, DA_C + DA_32 + DA_DPL3); SetDescValue(pt->ldt + LDT_DATA32_INDEX, 0x00, 0xFFFFF, DA_DRW + DA_32 + DA_DPL3); pt->ldtSelector = GDT_TASK_LDT_SELECTOR; pt->tssSelector = GDT_TASK_TSS_SELECTOR; SetDescValue(&gGdtInfo.entry[GDT_TASK_LDT_INDEX], (uint)&pt->ldt, sizeof(pt->ldt)-1, DA_LDT + DA_DPL0); SetDescValue(&gGdtInfo.entry[GDT_TASK_TSS_INDEX], (uint)&gTSS, sizeof(gTSS)-1, DA_386TSS + DA_DPL0); } void Delay(int n) { while( n > 0 ) { int i = 0; int j = 0; for(i=0; i<1000; i++) { for(j=0; j<1000; j++) { asm volatile ("nop "); } } n--; } } void TaskA() { int i = 0; SetPrintPos(0, 12); PrintString("Task A: "); while(1) { SetPrintPos(8, 12); PrintChar('A' + i); i = (i + 1) % 26; Delay(1); } } void TaskB() { int i = 0; SetPrintPos(0, 13); PrintString("Task B: "); while(1) { SetPrintPos(8, 13); PrintChar('0' + i); i = (i + 1) % 10; Delay(1); } } void ChangeTask() { gCTaskAddr = (gCTaskAddr == &p) ? &t : &p; gTSS.ss0 = GDT_DATA32_FLAT_SELECTOR; gTSS.esp0 = (uint)&gCTaskAddr->rv.gs + sizeof(RegValue); SetDescValue(&gGdtInfo.entry[GDT_TASK_LDT_INDEX], (uint)&gCTaskAddr->ldt, sizeof(gCTaskAddr->ldt)-1, DA_LDT + DA_DPL0); LoadTask(gCTaskAddr); } void TimerHandlerEntry(); void TimerHandler() { static uint i = 0; i = (i + 1) % 5; if( i == 0 ) { ChangeTask(); } SendEOI(MASTER_EOI_PORT); } void KMain() { int n = PrintString("D.T.OS "); uint temp = 0; PrintString("GDT Entry: "); PrintIntHex((uint)gGdtInfo.entry); PrintChar(' '); PrintString("GDT Size: "); PrintIntDec((uint)gGdtInfo.size); PrintChar(' '); PrintString("IDT Entry: "); PrintIntHex((uint)gIdtInfo.entry); PrintChar(' '); PrintString("IDT Size: "); PrintIntDec((uint)gIdtInfo.size); PrintChar(' '); InitTask(&t, TaskB); InitTask(&p, TaskA); SetIntHandler(gIdtInfo.entry + 0x20, (uint)TimerHandlerEntry); InitInterrupt(); EnableTimer(); gCTaskAddr = &p; RunTask(gCTaskAddr); }
loader.asm
%include "blfunc.asm" %include "common.asm" org BaseOfLoader interface: BaseOfStack equ BaseOfLoader BaseOfTarget equ BaseOfKernel Target db "KERNEL " TarLen equ ($-Target) [section .gdt] ; GDT definition ; Base, Limit, Attribute GDT_ENTRY : Descriptor 0, 0, 0 CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32 + DA_DPL0 VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32 + DA_DPL0 CODE32_FLAT_DESC : Descriptor 0, 0xFFFFF, DA_C + DA_32 + DA_DPL0 DATA32_FLAT_DESC : Descriptor 0, 0xFFFFF, DA_DRW + DA_32 + DA_DPL0 TASK_LDT_DESC : Descriptor 0, 0, 0 TASK_TSS_DESC : Descriptor 0, 0, 0 ; GDT end GdtLen equ $ - GDT_ENTRY GdtPtr: dw GdtLen - 1 dd 0 ; GDT Selector Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0 VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL0 Code32FlatSelector equ (0x0003 << 3) + SA_TIG + SA_RPL0 Data32FlatSelector equ (0x0004 << 3) + SA_TIG + SA_RPL0 ; end of [section .gdt] [section .idt] align 32 [bits 32] IDT_ENTRY: ; IDT definition ; Selector, Offset, DCount, Attribute %rep 256 Gate Code32Selector, DefaultHandler, 0, DA_386IGate + DA_DPL0 %endrep IdtLen equ $ - IDT_ENTRY IdtPtr: dw IdtLen - 1 dd 0 ; end of [section .idt] [section .s16] [bits 16] BLMain: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, SPInitValue ; initialize GDT for 32 bits code segment mov esi, CODE32_SEGMENT mov edi, CODE32_DESC call InitDescItem ; initialize GDT pointer struct mov eax, 0 mov ax, ds shl eax, 4 add eax, GDT_ENTRY mov dword [GdtPtr + 2], eax ; initialize IDT pointer struct mov eax, 0 mov ax, ds shl eax, 4 add eax, IDT_ENTRY mov dword [IdtPtr + 2], eax call LoadTarget cmp dx, 0 jz output call StoreGlobal ; 1. load GDT lgdt [GdtPtr] ; 2. close interrupt ; load IDT ; set IOPL to 3 cli lidt [IdtPtr] pushf pop eax or eax, 0x3000 push eax popf ; 3. open A20 in al, 0x92 or al, 00000010b out 0x92, al ; 4. enter protect mode mov eax, cr0 or eax, 0x01 mov cr0, eax ; 5. jump to 32 bits code jmp dword Code32Selector : 0 output: mov bp, ErrStr mov cx, ErrLen call Print jmp $ ; esi --> code segment label ; edi --> descriptor label InitDescItem: push eax mov eax, 0 mov ax, cs shl eax, 4 add eax, esi mov word [edi + 2], ax shr eax, 16 mov byte [edi + 4], al mov byte [edi + 7], ah pop eax ret ; ; StoreGlobal: mov dword [RunTaskEntry], RunTask mov dword [LoadTaskEntry], LoadTask mov dword [InitInterruptEntry], InitInterrupt mov dword [EnableTimerEntry], EnableTimer mov dword [SendEOIEntry], SendEOI mov eax, dword [GdtPtr + 2] mov dword [GdtEntry], eax mov dword [GdtSize], GdtLen / 8 mov eax, dword [IdtPtr + 2] mov dword [IdtEntry], eax mov dword [IdtSize], IdtLen / 8 ret [section .sfunc] [bits 32] ; ; Delay: %rep 5 nop %endrep ret ; ; Init8259A: push ax ; master ; ICW1 mov al, 00010001B out MASTER_ICW1_PORT, al call Delay ; ICW2 mov al, 0x20 out MASTER_ICW2_PORT, al call Delay ; ICW3 mov al, 00000100B out MASTER_ICW3_PORT, al call Delay ; ICW4 mov al, 00010001B out MASTER_ICW4_PORT, al call Delay ; slave ; ICW1 mov al, 00010001B out SLAVE_ICW1_PORT, al call Delay ; ICW2 mov al, 0x28 out SLAVE_ICW2_PORT, al call Delay ; ICW3 mov al, 00000010B out SLAVE_ICW3_PORT, al call Delay ; ICW4 mov al, 00000001B out SLAVE_ICW4_PORT, al call Delay pop ax ret ; al --> IMR register value ; dx --> 8259A port WriteIMR: out dx, al call Delay ret ; dx --> 8259A ; return: ; ax --> IMR register value ReadIMR: in ax, dx call Delay ret ; ; dx --> 8259A port WriteEOI: push ax mov al, 0x20 out dx, al call Delay pop ax ret [section .gfunc] [bits 32] ; ; parameter ===> Task* pt RunTask: push ebp mov ebp, esp mov esp, [ebp + 8] lldt word [esp + 200] ltr word [esp + 202] pop gs pop fs pop es pop ds popad add esp, 4 iret ; void LoadTask(Task* pt); ; LoadTask: push ebp mov ebp, esp mov eax, [ebp + 8] lldt word [eax + 200] leave ret ; ; InitInterrupt: push ebp mov ebp, esp push ax push dx call Init8259A sti mov ax, 0xFF mov dx, MASTER_IMR_PORT call WriteIMR mov ax, 0xFF mov dx, SLAVE_IMR_PORT call WriteIMR pop dx pop ax leave ret ; ; EnableTimer: push ebp mov ebp, esp push ax push dx mov dx, MASTER_IMR_PORT call ReadIMR and ax, 0xFE call WriteIMR pop dx pop ax leave ret ; void SendEOI(uint port); ; port ==> 8259A port SendEOI: push ebp mov ebp, esp mov edx, [ebp + 8] mov al, 0x20 out dx, al call Delay leave ret [section .s32] [bits 32] CODE32_SEGMENT: mov ax, VideoSelector mov gs, ax mov ax, Data32FlatSelector mov ds, ax mov es, ax mov fs, ax mov ax, Data32FlatSelector mov ss, ax mov esp, BaseOfLoader jmp dword Code32FlatSelector : BaseOfKernel ; ; DefaultHandlerFunc: iret DefaultHandler equ DefaultHandlerFunc - $$ Code32SegLen equ $ - CODE32_SEGMENT ErrStr db "No KERNEL" ErrLen equ ($-ErrStr) Buffer db 0
更多代码见相关课程