學習作業系統原理最好的方法是自己寫一個簡單的作業系統。
在QEMU中會預設輸出一些字元,有時候會干擾我們自己輸出的字元。一個比較好的辦法是向將螢幕清空,再輸出我們想要輸出的字元。下面就來學習如何清空螢幕。
其實清空螢幕的原理很簡單,就是將螢幕寫滿空格就行了。
下面來實戰。mbr8.asm程式碼如下:
;定義常數(作用和C語言中的#define一樣)
VIDEO_CHAR_MAX_COUNT equ 2000 ;預設螢幕最多顯示字元數。
org 0x7c00
;初始化段暫存器
mov ax,0xb800
mov es,ax ;本程式中es專用於指向視訊記憶體段
;清屏
call func_clear_screen
stop:
hlt
jmp stop
;清屏函數(將螢幕寫滿空格就實現了清屏)
;輸入引數:無。
;輸出引數:無。
func_clear_screen:
mov ah,0x00 ;黑底黑字
mov al,' ' ;空格
mov cx,VIDEO_CHAR_MAX_COUNT ;迴圈控制
.start_blank:
mov bx,cx ;以下3行表示bx=(cx-1)*2
dec bx
shl bx,1
mov [es:bx],ax ;[es:bx]表示字元對應的視訊記憶體地址(從螢幕右下角往前清屏)
loop .start_blank
ret
times 510-($-$$) db 0
db 0x55,0xaa
編譯執行截圖如下:
從上面QEMU截圖可以看到,之前QEMU預設輸出的字元已經沒有了,螢幕清空的很乾淨。
一般我們都是先清空螢幕,再輸出自己想要輸出的字串。
下面我們來看mbr9.asm的程式碼:
;定義常數(作用和C語言中的#define一樣)
VIDEO_CHAR_MAX_COUNT equ 2000 ;預設螢幕最多顯示字元數。
org 0x7c00 ;如果沒有該行將無法正確列印要顯示的字串
;初始化段暫存器
mov ax,cs
mov ds,ax ;ds指向與cs相同的段
mov ax,0xb800
mov es,ax ;本程式中es專用於指向視訊記憶體段
;清屏
call func_clear_screen
;列印字串
mov si,string1
mov di,0 ;在螢幕第1行顯示
call func_print_string
stop:
hlt
jmp stop
;清屏函數(將螢幕寫滿空格就實現了清屏)
;輸入引數:無。
;輸出引數:無。
func_clear_screen:
mov ah,0x00 ;黑底黑字
mov al,' ' ;空格
mov cx,VIDEO_CHAR_MAX_COUNT ;迴圈控制
.start_blank:
mov bx,cx ;以下3行表示bx=(cx-1)*2
dec bx
shl bx,1
mov [es:bx],ax ;[es:bx]表示字元對應的視訊記憶體地址(從螢幕右下角往前清屏)
loop .start_blank
ret
;列印字串函數。
;輸入引數:ds:si,di。
;輸出引數:無。
;ds:si 表示字串起始地址,以0為結束符。
;di 表示字串在螢幕上顯示的起始位置(0~1999)。
func_print_string:
mov ah,0x07 ;ah表示字元屬性,0x07表示黑底白字。
shl di,1 ;乘2(螢幕上每個字元對應2個視訊記憶體位元組)。
.start_char: ;以點開頭的標號為區域性標號,完整形式是 func_print_string.start_char,但在同一個全域性標號func_print_string內部不需要寫完整形式。
mov al,[si]
cmp al,0
jz .end_print
mov [es:di],ax ;將字元和屬性放到對應的視訊記憶體中。
inc si
add di,2
jmp .start_char
.end_print:
ret
string1:db "Hello GrapeOS!",0
times 510-($-$$) db 0
db 0x55,0xaa
mbr9.asm其實就是將mbr8.asm和mbr7.asm合併了一下。
下面來看編譯執行截圖:
從上面的QEMU截圖中可以看到,我們在清空的螢幕上第一行顯示了字串「Hello GrapeOS!」,這就是我們想要的效果。
本講視訊版地址:https://www.bilibili.com/video/BV1DD4y137ET/
本教學程式碼和資料:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS作業系統QQ群:643474045