Antz系統更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html
Linux內核源碼分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html
在前幾天的任務中,我們已經簡單實現了MBR,直接操作顯示器和硬盤操作來加載其他扇區的程序,如今已經可以進入保護模式了,之前一直使用的是匯編語言,接下來要使用c語言實現內核了。
0. GCC前提
gcc -c -o main.o main.c
-c的作用是編譯,匯編到目標代碼,不進行鏈接,也就是直接生成目標文件。
-o的作用是將輸出的文件以指定文件名來存儲,有同名文件會直接覆蓋。
如果你不會使用GCC,請先去略作了解。
這行命令會生成一個main.o文件。它只是一個目標文件,也是待重定位文件,重定位是指文件里面所用的符號還沒有安排地址,這些符號的地址要與其他目標文件組成一個可執行文件時再重新定位(排地址),符號是指該目標文件中所調用的函數或使用的變量,這里的組成就是指鏈接。
main.o是可重定位文件,ld命令可以鏈接,指定最終生成文件的起始虛擬地址。
ld main.o -Ttext 0xc0001500 -e main -o main.bin
-Ttext指定了起始虛擬地址是0xc0001500,這個地址是內核加載需要的,-o是指定輸出文件,-e是指定了程序起始地址。
1. 引入C語言
內核,是一個操作系統的核心。是基於硬件的第一層軟件擴充,提供操作系統的最基本的功能,是操作系統工作的基礎,它負責管理系統的進程、內存、設備驅動程序、文件和網絡系統,決定着系統的性能和穩定性。
現代操作系統設計中,為減少系統本身的開銷,往往將一些與硬件緊密相關的(如中斷處理程序、設備驅動程序等)、基本的、公共的、運行頻率較高的模塊(如時鍾管理、進程調度等)以及關鍵性數據結構獨立開來,使之常駐內存,並對他們進行保護。通常把這一部分稱之為操作系統的內核。
程序可以直接地被調入計算機中執行,這樣的設計說明了設計者不希望提供任何硬件抽象和操作系統的支持,它常見於早期計算機系統的設計中。最終,一些輔助性程序,例如程序加載器和調試器,被設計到機器核心當中,或者固化在只讀存儲器里。這些變化發生時,操作系統內核的概念就漸漸明晰起來了。
antz_os.asm :
1 ; antz_os 2 3 4 BOTPAK EQU 0x00280000 5 DSKCAC EQU 0x00100000 6 DSKCAC0 EQU 0x00008000 7 8 9 CYLS EQU 0x0ff0 10 LEDS EQU 0x0ff1 11 VMODE EQU 0x0ff2 12 SCRNX EQU 0x0ff4 13 SCRNY EQU 0x0ff6 14 VRAM EQU 0x0ff8 15 16 ORG 0xc200 17 18 19 20 MOV AL,0x13 21 MOV AH,0x00 22 INT 0x10 23 MOV BYTE [VMODE],8 24 MOV WORD [SCRNX],320 25 MOV WORD [SCRNY],200 26 MOV DWORD [VRAM],0x000a0000 27 28 29 30 MOV AH,0x02 31 INT 0x16 ; keyboard BIOS 32 MOV [LEDS],AL 33 34 35 36 37 38 39 MOV AL,0xff 40 OUT 0x21,AL 41 NOP 42 OUT 0xa1,AL 43 44 CLI 45 46 47 48 CALL waitkbdout 49 MOV AL,0xd1 50 OUT 0x64,AL 51 CALL waitkbdout 52 MOV AL,0xdf ; enable A20 53 OUT 0x60,AL 54 CALL waitkbdout 55 56 ; 保護模式轉換 57 58 [INSTRSET "i486p"] 59 60 LGDT [GDTR0] 61 MOV EAX,CR0 62 AND EAX,0x7fffffff 63 OR EAX,0x00000001 64 MOV CR0,EAX 65 JMP pipelineflush 66 67 MOV AX,1*8 68 MOV DS,AX 69 MOV ES,AX 70 MOV FS,AX 71 MOV GS,AX 72 MOV SS,AX 73 74 75 76 MOV ESI,bootpack ; 源 77 MOV EDI,BOTPAK ; 目標 78 MOV ECX,512*1024/4 79 CALL memcpy 80 81 82 83 84 85 MOV ESI,0x7c00 ; 源 86 MOV EDI,DSKCAC ; 目標 87 MOV ECX,512/4 88 CALL memcpy 89 90 91 92 MOV ESI,DSKCAC0+512 ; 源 93 MOV EDI,DSKCAC+512 ; 目標 94 MOV ECX,0 95 MOV CL,BYTE [CYLS] 96 IMUL ECX,512*18*2/4 97 SUB ECX,512/4 98 CALL memcpy 99 100 101 102 103 104 105 MOV EBX,BOTPAK 106 MOV ECX,[EBX+16] 107 ADD ECX,3 108 SHR ECX,2 109 JZ skip 110 MOV ESI,[EBX+20] 111 ADD ESI,EBX 112 MOV EDI,[EBX+12] 113 CALL memcpy 114 skip: 115 MOV ESP,[EBX+12] 116 JMP DWORD 2*8:0x0000001b 117 118 waitkbdout: 119 IN AL,0x64 120 AND AL,0x02 121 JNZ waitkbdout 122 RET 123 124 memcpy: 125 MOV EAX,[ESI] 126 ADD ESI,4 127 MOV [EDI],EAX 128 ADD EDI,4 129 SUB ECX,1 130 JNZ memcpy 131 RET 132 133 134 ALIGNB 16 135 GDT0: 136 RESB 8 137 DW 0xffff,0x0000,0x9200,0x00cf 138 DW 0xffff,0x0000,0x9a28,0x0047 139 DW 0 140 GDTR0: 141 DW 8*3-1 142 DD GDT0 143 144 ALIGNB 16 145 bootpack:
bootpack.c:
1 void io_hlt(void); 2 void write_mem8(int addr,int data); 3 4 void HariMain(void) 5 { 6 int i ; 7 for(i=0xa0000;i<0xaffff;i++){ 8 write_mem8(i,15); 9 } 10 for(;;){ 11 io_hlt(); 12 } 13 }
func.asm:
1 [FORMAT "WCOFF"] 2 [BITS 32] 3 [INSTRSET "i486p"] 4 5 [FILE "naskfunc.nas"] 6 7 GLOBAL _io_hlt 8 9 [SECTION .text] 10 11 _io_hlt: ; void io_hlt(void); 12 HLT 13 RET 14 15 _write_mem8: 16 MOV ECX,[ESP+4] 17 MOV AL,[ESP+8] 18 MOV [ECX],AL 19 RET
在func.asm中聲明了bootpack.c中調用的函數,用於繪制屏幕,如果你還不了解怎么繪制屏幕,可以看看第三天的直接操作顯卡部分。
生成的img打開在虛擬機之后。
看到這里你可能會發現,我們在c語言中定義的函數完成了屏幕繪制,在HariMain函數中的for循環將整個屏幕完成了繪制。write_mem8函數的兩個參數分別控制了位置和顏色,這是圖形化的一大步。
隨意修改一下參數之后,屏幕顯示就是不一樣的顏色了,至於怎么改,可以在for循環里面自行修改了。
關於內核的知識便不再向之前一樣詳細概況了,推薦一本書,《Linux內核完全剖析》。