一步步编写操作系统 76 用汇编语言编写字符打印函数
之前咱們介紹顯卡上那么多的寄存器終于發揮用處了,我們看看前文中介紹的表CRT Controller Data Registers中索引為0Eh的 Cursor Location High Register寄存器和索引為0Fh的Cursor Location Low Register寄存器,這兩個寄存器都是8位長度。分別用來存儲光標坐標的低8位和高8位地址。
訪問CRT controller寄存器組的寄存器,需要先往端口地址為0x3D4的Address Register寄存器中寫入寄存器的索引,再從端口地址為0x3D5的Data Register寄存器讀、寫數據。
接著解釋之前的代碼(本文是連載,沒看過前面,估計本節是蒙逼的)
1 TI_GDT equ 02 RPL0 equ 03 SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL045 [bits 32]6 section .text7 ;------------------------ put_char -----------------------------8 ;功能描述:把棧中的1個字符寫入光標所在處9 ;-------------------------------------------------------------------10 global put_char11 put_char:12 pushad ;備份32位寄存器環境13 ;需要保證gs中為正確的視頻段選擇子,;為保險起見,每次打印時都為gs賦值14 mov ax, SELECTOR_VIDEO ; 不能直接把立即數送入段寄存器 15 mov gs, ax1617 ;;;;;;;;; 獲取當前光標位置 ;;;;;;;;;18 ;先獲得高8位19 mov dx, 0x03d4 ;索引寄存器20 mov al, 0x0e ;用于提供光標位置的高8位21 out dx, al22 mov dx, 0x03d5 ;通過讀寫數據端口0x3d5來獲得或設置光標位置23 in al, dx ;得到了光標位置的高8位24 mov ah, al2526 ;再獲取低8位27 mov dx, 0x03d428 mov al, 0x0f29 out dx, al30 mov dx, 0x03d531 in al, dx3233 ;將光標存入bx34 mov bx, ax35 ;下面這行是在棧中獲取待打印的字符36 mov ecx, [esp + 36] ;pushad壓入4×8=32字節,;加上主調函數4字節的返回地址,故esp+36字節37 cmp cl, 0xd ;CR是0x0d,LF是0x0a38 jz .is_carriage_return39 cmp cl, 0xa40 jz .is_line_feed4142 cmp cl, 0x8 ;BS(backspace)的asc碼是843 jz .is_backspace44 jmp .put_other在代碼第17~31行用來獲取光標值,先在第19~21行設置待操作的寄存器索引,我們先獲取的是坐標的高8位,所以要將索引0x0e寫入Address Register寄存器,其端口為0x03d4。
確定了要操作的寄存器是Cursor Location High Register后,我們在第22~24行通過Data Register寄存器,其端口是0x3d5,將坐標讀入到al寄存器,由于al中是坐標的高8位,所以第24行將其存儲在ah寄存器。也許您心存疑惑,既然要把坐標的高8位存到寄存器ah中,為什么不把in指令中的al換成ah,變成in ah, dx?還多搗騰一次干嗎?真的抱歉,對于in指令,如果源操作是8位寄存器,目的操作數必須是al,如果源操作數是16位寄存器,目的操作數必須是ax。
第26~32行用同樣的方法獲取到坐標的低8位,至此,寄存器ax中是光標完整的16位坐標值。
第35行是將光標值從ax寄存器中復制到bx,這么做的原因是習慣用寄存器bx做基址尋址,還記得嗎,在16位實模式下基址寄存器必須是bx或bp,變址必須是寄存器si或di。在32位保護模式下沒必要這么做了,基址和變址寄存器可以是全部的32位的通用寄存器,就是剛才用pushad指令壓入的那8個,忘了往上翻翻。以后的處理都要基于bx寄存器了,在此知道bx現在已經是光標坐標值就行了,它是下一個可打印字符的位置。
第36行是獲取棧中壓入的字符的ascii碼,也就是待打印的字符,這是1字節的數據。棧中除了調用put_char函數的返回地址占4字節外,還有最開始的pushad指令壓入的8個32位的通用寄存器共32字節的數據,所以待打印的字符在棧頂偏移36字節的位置。
之后的第36~44行開始判斷參數是什么字符,咱們這里只把回車符CR(carriage_return)、換行符LF(line_feed)和退格鍵backspace當做不可見字符,按照其實際控制意義來處理,其它字符暫時一律認為是可見字符。回車符的ascii碼是0xd,換行符的ascii碼是0xa,我們這里的處理是,不管參數是回車符,還是換行符,一律按我們平時所理解的回車換行符(CRLF)處理(linux中就把換行符處理成回車+換行),即這兩個動作的合成:光標回撤到行首+換到下一行。
本文是連續劇哦,所以得看過之前的文章才行。下班
總結
以上是生活随笔為你收集整理的一步步编写操作系统 76 用汇编语言编写字符打印函数的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 一步步编写操作系统 27 处理器微架构之
- 下一篇: 挖财信用卡管家安全吗
