昨天我們談到顯示設備在虛擬化環境中的運作邏輯,也說明了主機端能觀察畫面變化的策略。
一種是透過 EPT 寫保護 或 MMIO 映射 強制每次寫入都觸發 VM-exit,另一種是讓 Host 端定期去輪詢 framebuffer 的內容,透過 dirty log 或簡單的取樣方式去刷新畫面。
前者更可以即時反映事件邏輯,但如果我們從顯示設備的角度去看,會發現第二種方式更接近真實行為。顯示行為從來不是即時的,CPU 寫入 frame buffer 的那一刻,畫面並不會馬上改變。frame buffer 只是顯示器的資料來源,顯示器是已固定頻率去掃描那塊記憶體,並將資料輸出成影像信號。
如果我們在虛擬環境中,把 framebuffer 所在的頁面註冊為 MMIO 區域或設成 EPT 寫保護,那麼每次 Guest 對畫面做出任何寫入,(哪怕只是修改了一個字元或一個像素)都會觸發 VM-exit。Host 會在每一次寫入後立刻捕捉事件、重新刷新畫面。這樣做的確能讓畫面「同步」,但這種同步的粒度遠比真實顯示器更細。
在實際硬體中,螢幕的刷新頻率通常是 60Hz 或 120Hz,而在 BIOS 或 early-boot 階段,我們可能需要大量的輸出(例如列印 log、狀態提示),這些操作可能讓造成 CPU 每秒對 framebuffer 寫入上千次資料。如果這些寫入全部都轉成 VM-exit,主機端就會在短時間內處理上千次 context switch,也會嚴重消耗性能。
相比之下,我們讓 Host 端以固定時間間隔(例如 50ms,也就是 20Hz)去掃描 framebuffer,更貼近真實顯示器的行為。這樣一來,畫面的更新不再被動依附在 CPU 的寫入操作上,而是由一個獨立的刷新機制主導。
今天的 BIOS 實作將建立在昨天的基礎。實作了一個簡易的 INT 10h handler,讓 BIOS 可以直接把字元寫入 0xB8000 的文字模式區域。我們來實現 INT 10h 的基礎功能,06h(捲動與清屏)、02h(設定游標位置)、13h(顯示字串)。
這個功能的作用是讓顯示游標移動到指定位置。使用前須定義以下暫存器:
AH = 02h ; 功能號
BH = 頁碼
DH = 游標列號 (row)
DL = 游標行號 (column)
這個功能能控制整個文字區域的滾動,當滾動行數設為 0 時,就會清除整個螢幕。
AH = 06h ; 功能號
AL = 滾動的列(row)數 (設 0 = 清屏)
BH = 空白區的顏色屬性
CH, CL = 滾動區域左上角(row, col)
DH, DL = 滾動區域右下角(row, col)
舉例來說,以下程式會把整個畫面清成黑底白字:
mov ax, 0600h ; AH=06h, AL=00h => 清屏
mov bh, 07h ; 白字黑底
mov cx, 0 ; 左上角 (0,0)
mov dx, 184Fh ; 右下角 (24,79)
int 10h
BH 的屬性值瘸定顯示顏色。
Bit | 名稱 | 說明 |
---|---|---|
7 | Blink / High Background | 0:不閃爍;1:字體閃爍(部分 VGA 會解釋成高亮背景) |
6–4 | 背景色索引(0–7) | 指定背景顏色(黑、藍、綠、青、紅、紫、棕、白) |
3 | 亮度(Intensity) | 0:正常亮度;1:高亮字體 |
2–0 | 字體色索引 (0–7) | 指定字體顏色(黑、藍、綠、青、紅、紫、棕、白) |
AH = 13h ; 功能號
AL = 寫入模式 ; 00h/01h/02h/03h (子功能號)
BH = 頁碼
BL = 顏色屬性
CX = 字串長度
DH, DL = 游標位置
ES:BP = 字串的記憶體地址
子功能號 (AL) 定義如下:
AL | 說明 |
---|---|
00h | 使用 BL 顏色屬性,不移動游標 |
01h | 使用 BL 顏色屬性,並移動游標到字串結尾 |
02h | 每個字元後緊接屬性位元,字串長度以 word 計算,不移動游標 |
03h | 同上,但會移動游標到字串結尾 |
另外 BL 顏色屬定的定義同 10h 的那張表的 8 bit。 | |
舉例來說,我們想在第 5 列、第 10 行印出一行藍底白字訊息可以這樣寫 |
mov ax, 1301h ; AH=13h, AL=01h 顯示字串後移動游標
mov bh, 0 ; 頁碼
mov bl, 1Fh ; 白字藍底(高亮)
mov cx, msg_len ; 字串長度
mov dh, 5 ; 第 5 列
mov dl, 10 ; 第 10 行
push cs
pop es
mov bp, msg ; ES:BP 指向字串
int 10h
另外這 BH 頁碼其實是一種 text buffer,也就是一種顯示頁,VGA 文字模式會預留多個緩衝區,以便程式在不同頁面之間切換顯示內容。