OrzMicrokernel bit32.asm 進入保護模式後的核心初始化

OrzMicrokernel 在 bit16.asm 完成了轉換成保護模式的工作,緊接著會跳到 bit32.asm 初始化核心和設定硬體中斷周期。最重要的是,從跳轉到這檔案後,就可以開始使用 32 位元的各種延伸暫存器以及更大的記憶體定址,但前題是:我們得先將新的暫存器區段位址設定好,因為暫存器設定還是處於在真實模式時的狀態。

程式碼和詳細註解:
[BITS 32]
; Intel 處理器的設計是以 dword 為單位來存取記憶體,所以記憶體位址定為 4 的倍數。
align 4 ; 設定所有資料的起始位址都是 4 的倍數
Begin32c:
; 初始化暫存器區段
mov ax, kernel_data - _GDT ; 從 tables.asm 的 kernel_data 開始
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x2FFFF ; 堆疊暫存器設在 2MB 記憶體後

call TestMemory ; 呼叫 mm.asm 的子程式測試記憶體

mov edi, memMap ; 初始化索引暫存器
;
memMap 記憶體大小有0x20000=128KB
mov ecx, 0x100 / 32 ; 計數器設為 256/32=8
xor eax, eax ; 將 eax 歸零
dec eax
rep stosd ; 每次從 EAX 中複製 4 Bytes 到 EDI
; 複製 8 次


mov ecx, 0x20000 / 4 - (0x100 / 32) ; 計數器設為 32760
xor eax,eax ; 將 eax 歸零
rep stosd ; 每次從 EAX 中複製 4 Bytes 到 EDI
; 複製 32760 次


; 設定 825x 計時器
; 模式控制暫存器(I/O 埠編號 43H):共 8 位元
;
; 位元 位元值 說明
; 0 0 使用二進位格式的數值
; 1 使用 BCD 格式的數值
; 1,2,3 000 計時模式 0
; 001 計時模式 1
; 010 計時模式 2
; 011 計時模式 3
; 100 計時模式 4
; 101 計時模式 5
; 4,5 00 保留住目前數值
; 01 僅讀寫較高的位元組
; 10 僅讀寫較低的位元組
; 11 先讀寫較低的位元組,再讀寫較高的位元組
; 7,6 00 選擇計時通道 0
; 01 選擇計時通道 1
; 10 選擇計時通道 2
; 11 指定讀回命令
mov al, 0x34 ; 設定計時器
; 設定值為 00110100:
; 使用二進位格式的數值
; 計時模式 2
; 先讀寫較低的位元組,再讀寫較高的位元組
; 選擇計時通道 0
out 0x43, al ; 設定 AL 至模式控制暫存器

; 設定時間周期為 10ms(100Hz)
; 即每 10ms 產生一次中斷信號
; 設定值算法:1193180 / 100 = 11931 = 0x2e9b
; 石英震盪器每秒震盪 1193180 次
; 頻率 100Hz
mov al, 0x9b ; 先設定低位元 0x9b
out 0x40, al ; 輸入到計時器0
mov al, 0x2e ; 再設定高位元 0x2e
out 0x40, al ; 輸入到計時器0

call EnableIRQs ; 呼叫 irqs.asm 的子程式以啟動 IRQ 機制



後記

這次比較特別的部份,就是牽扯到 Timer 的操作,我想應該只有少數的 Programer 有機會直接接觸到 825x 計時器,我們過去還得靠它才能讓 PC Speaker 發出難聽的電子旋律呢!(笑)

這個網誌中的熱門文章

Web 技術中的 Session 是什麼?

淺談 USB 通訊架構之定義(一)

淺談 USB 通訊架構之定義(二)

JavaScript 好用的 async 異步函數!

使用 NodeJS + Express 從 GET/POST Request 取值