30天自制操做系統-4

首先啊,今天的內容比較多,但你們能夠直接看書最後面,一想到作完後就能看到這個界面上有咱們畫上去的東西就開心納,朝着這個盡頭,開始吧。數組

首先就是用C語言寫內存,若是用匯編寫的話,就是用[]這種來進行內存讀寫,其實咱們就是要在彙編裏封裝一些函數讓C去調用。這裏忽然想起了,作手遊,爲了熱更新,也是這個套路。函數

_write_mem8:    ; void write_mem8(int addr, int data);
    MOV        ECX,[ESP+4]        ; [ESP+4]‚中存放的是地址,將其讀入ECX
    MOV        AL,[ESP+8]        ; [ESP+8]‚中存放的是數據,將其讀入AL
    MOV        [ECX],AL
    RET

首先,寫了個函數叫write_mem8,其意是向內存地址中寫入8個字節,因此用的是AL。
函數自己也很簡單,做者在這裏作了說明,只能用EAX,ECX,EDX,由於用於記憶C語言編譯後的機器語言中。
[INSTRSET "i486p"] ; 486‚指定用於486,固然也不是說其餘的就不能用。操作系統

int i;

for (i = 0xa0000; i <= 0xaffff; i++) {
    write_mem8(i, i & 0x0f);
}

for (;;) {
    io_hlt();
}

註釋也省略了,由於我以爲到了C語言,應該沒有什麼語法看不懂的了,主要是思惟。昨天已經介紹過0xa00000-0xaffff是使用這個模式,對這部份內存操做就是對最終屏幕繪製出來的內容密切相關。線程

條紋圖案指針

這裏巧妙的運用了AND運算符,因爲每次遍歷出來一個字節,8位,與0x0f與運算,也就是0x0f有低四位可是高四位是0。因爲i、每隔16進一次位,因此每隔16次反覆進行此運算,而這16此每一次的計算,保留低4位,由於f的存在,高四位變成0由於0x0f中0的存在。code

指針
理所固然C語言的指針就是拿來玩兒內存的,多是讀者爲了讓咱們更瞭解原理,而後寫了以前的read_mem8這個函數。若是直接對i進行取地址,那他固然不知道這個地址是個什麼類型,固然也就不知道賦值多少位過去,因此寫了個char *p
指針在專欄裏做者講了一大堆,若是能看懂,哦,做者講的確實對。但我以爲對於初學者,去學一些C語言的書,多看些打印的值,更直觀些。說個我也會忘的知識吧 a[1] 1[a]是同樣的意思。遊戲

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);ip

// 就算寫在同一個源文件裏,在使用以前必須聲明一下,若是函數在前面則不用內存

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);it

void HariMain(void)
{

int i; // 聲明變量,這裏的變量i是32位整型
char *p; // 變量p是Byte[...]用的地址

init_palette(); // 設定調色板

p = (char *) 0xa0000; // 指定地址

for (i = 0; i <= 0xffff; i++) {
    p[i] = i & 0x0f;
}

for (;;) {
    io_hlt();
}

}

void init_palette(void)
{

static unsigned char table_rgb[16 * 3] = {
    0x00, 0x00, 0x00,    
    0xff, 0x00, 0x00,    
    0x00, 0xff, 0x00,    
    0xff, 0xff, 0x00,    
    0x00, 0x00, 0xff,    
    0xff, 0x00, 0xff,    
    0x00, 0xff, 0xff,    
    0xff, 0xff, 0xff,    
    0xc6, 0xc6, 0xc6,    
    0x84, 0x00, 0x00,    
    0x00, 0x84, 0x00,    
    0x84, 0x84, 0x00,    
    0x00, 0x00, 0x84,    
    0x84, 0x00, 0x84,    
    0x00, 0x84, 0x84,    
    0x84, 0x84, 0x84    
};
set_palette(0, 15, table_rgb);
return;

// C語言中的static char語句只能用於數據,至關於彙編中的DB指令

}

void set_palette(int start, int end, unsigned char *rgb)
{

int i, eflags;
eflags = io_load_eflags();    // 記錄中斷許可標誌的值
io_cli();                     // 將中斷許可標誌置爲0,禁止中斷
io_out8(0x03c8, start);
for (i = start; i <= end; i++) {
    io_out8(0x03c9, rgb[0] / 4);
    io_out8(0x03c9, rgb[1] / 4);
    io_out8(0x03c9, rgb[2] / 4);
    rgb += 3;
}
io_store_eflags(eflags);    // 復原中斷許可標誌
return;

}

代碼有點長,不過聲明就佔了好些行數。記得無論之前是學C仍是其餘高級語言對於靜態變量的說法都是,靜態存儲區,特有的存儲區。具備全局性等,但如今若是從彙編的角度來看,好像會對他產生全新的認識。記住static就至關於在彙編使用DB同樣。做者說這個方式a[0] = 1;佔三個字節的緣由多是賦值語句轉換位彙編是mov ....多是這樣致使的,因此改爲static就能避免不少這樣的操做。
咱們初始咱們想要的顏色後,如今要設定到調色板裏去。雖然做者說讓咱們先不理解io_out這個函數,但我以爲有點奇怪,一直往一個地址裏面寫值,不久把以前的覆蓋了嗎?仍是我寫一個,就會有相應的東西把值取走,而後保存下來?
有兩個函數CLI與STL這兩個配合起來意思是我在作這段代碼的過程當中不準任何人打攪,感受有點像高級語言的線程鎖。

前面幾個函數相對簡單,我直接來搞後兩個新函數。若是以前知道push和pop的來理解也就不難,PUSHFD先把eflags的值存在棧裏面,而後又放到EAX裏面去(不知道爲何做者沒講,要想返回函數的值,放到EAX裏面就行了,因此在C語言咱們能夠接收到一個返回值)。因爲這個值到C那邊跑了一圈,又傳回來了,因此咱們再入棧,在POPFD又回到了EFLAGS裏邊兒。

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{

int x, y;
for (y = y0; y <= y1; y++) {
    for (x = x0; x <= x1; x++)
        vram[y * xsize + x] = c;
}
return;

}

看到這裏更帶勁兒了,由於畫出了個正方形,來看看這個函數,思想也比較簡答, 就是塊數組,指定區域用指定值,而後對應的就是指定屏幕變成指定顏色。像這種常值的值,定義成define就好。

void HariMain(void)
{

char *vram;
int xsize, ysize;

init_palette();
vram = (char *) 0xa0000;
xsize = 320;
ysize = 200;

boxfill8(vram, xsize, COL8_008484,  0,         0,          xsize -  1, ysize - 29);
boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 28, xsize -  1, ysize - 28);
boxfill8(vram, xsize, COL8_FFFFFF,  0,         ysize - 27, xsize -  1, ysize - 27);
boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 26, xsize -  1, ysize -  1);

boxfill8(vram, xsize, COL8_FFFFFF,  3,         ysize - 24, 59,         ysize - 24);
boxfill8(vram, xsize, COL8_FFFFFF,  2,         ysize - 24,  2,         ysize -  4);
boxfill8(vram, xsize, COL8_848484,  3,         ysize -  4, 59,         ysize -  4);
boxfill8(vram, xsize, COL8_848484, 59,         ysize - 23, 59,         ysize -  5);
boxfill8(vram, xsize, COL8_000000,  2,         ysize -  3, 59,         ysize -  3);
boxfill8(vram, xsize, COL8_000000, 60,         ysize - 24, 60,         ysize -  3);

boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize -  4, ysize - 24);
boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize -  4);
boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize -  3, xsize -  4, ysize -  3);
boxfill8(vram, xsize, COL8_FFFFFF, xsize -  3, ysize - 24, xsize -  3, ysize -  3);

for (;;) {
    io_hlt();
}

}

這段代碼運行後,簡直是太棒啦,感受有點想咱們的桌面了,但其實仍是前面的知識,只是巧妙的利用了boxfill8這個函數。

大概解釋一下吧,第一個boxfill8是繪製桌面的感受,一張藍綠色的低,從左上角到離右下角y29,x1的位置,至於爲何做者在x方向少了一個1不太理解,多是留出邊緣吧。第二個是繪製一個桌面與狀態欄的灰色分割線。而後是藍色分割線,以此。。。還有一個辦法看每一行到底作了哪些東西,能夠一句代碼一句代碼的註釋,而後看效果。實話說這個操做系統是真的小,像我作exe,apk,ipa什麼的隨便弄個空項目出來就好幾百K,甚至用遊戲引擎的話,隨隨便便就是幾MB,簡直不敢想象,那個在咱們看來是個空項目,內部到底有多少代碼。

寫在最後我記得我在編譯這一天代碼的時候出現過一個問題, 不過最後也找到了,就是路徑問題,請你們注意一下,tolsetz_toolsharibote這個路徑下的haribote.rul文件內容的路徑必定也要修改,否則make run會報錯。

相關文章
相關標籤/搜索