#include "asm.h"
#include "memlayout.h"
#include "mmu.h"緩存
.code16
.globl start
start:
cli # 關中斷, 防止干擾開啓A20, 和保證設置GDT的完整性
# 初始化寄存器
xorw %ax,%ax # 將ax清零, 類似的方法如: movw $0, %ax , subw %ax, %ax
movw %ax,%ds # -> Data Segment
movw %ax,%es # -> Extra Segment
movw %ax,%ss # -> Stack Segmentoop
# 開啓A20spa
# A20地址線並非打開保護模式的關鍵, 只是不開A20, 沒法使用1MB以上的內存調試
# 由於歷史緣由, 在計算機啓動時, 是處於實模式下, A20是關閉狀態, 超出1MB內存會回捲code
# 開啓A20, 有三種方法,這只是其中一種索引
# 理論上講, 打開A20的方法就是設置8042芯片輸出端口(64h), 當該輸出端口位1爲1時就開啓了A20信號線.內存
#但實際上, 當你向8042芯片輸出端口進行寫操做時, 在鍵盤緩衝區中, 或許還有別的數據還沒有處理, 所以必須先處理這些數據, 這也是關中斷的緣由之一.
it
seta20.1:asm
#經過0x64端口, 讀取8042芯片的8位狀態寄存器(Status Register).
inb $0x64,%al test
# 當輸入緩存區爲空時, 狀態寄存器的值就會是0x2.
testb $0x2,%al
# 當狀態寄存器的值不是0x2, 繼續執行seta20.1,直到輸入緩存器爲空.
jnz seta20.1
# 將D1h寫入端口0x64,表示準備寫輸出端口 , 隨後經過60h端口寫入的字節,會被放置在輸出端口(64h)中。
movb $0xd1,%al
outb %al,$0x64
seta20.2:
inb $0x64,%al
testb $0x2,%al
jnz seta20.2
# 經過60端口,將0xdf寫入輸出端口(64h中)
movb $0xdf,%al # 0xdf -> port 0x60
outb %al,$0x60
# 加載GDT
# 後面有GDT的介紹, 共定義了三個段
# intel規定的全爲零的一個, 索引號爲0
# 基址爲零, 長度爲4G的代碼段, 索引號爲1
# 基址爲零, 長度爲4G的數據段, 索引號位2
lgdt gdtdesc
# 開啓保護模式
# CR0中包含了6個預約義標誌,0位是保護容許位PE(Protedted Enable),用於啓動保護模式,若是PE位置1,則保護模式啓動
movl %cr0, %eax
orl $CR0_PE, %eax # CR0_PE = 0x00000001
movl %eax, %cr0
# 進入保護模式, 跳轉到start32
# SEG_KCODE=1, 左移三位是由於段索引的低3位, 有其餘用處, 因此段索引號都乘以8, 即左移三位
# 使用ljmp是由於要將CS指向代碼段, 啓用保護模式下的段:偏移模式
ljmp $(SEG_KCODE<<3), $start32
.code32 # 32位代碼段開始標誌
start32:
# 初始化數據段寄存器
movw $(SEG_KDATA<<3), %ax # SEG_KDATA等於2
movw %ax, %ds # -> DS: Data Segment
movw %ax, %es # -> ES: Extra Segment
movw %ax, %ss # -> SS: Stack Segment
movw $0, %ax # 不使用FS和GS
movw %ax, %fs # -> FS
movw %ax, %gs # -> GS
# 設置棧頂, $start的地址是0x0000 7c00
movl $start, %esp
# 進入C語言編寫的代碼
call bootmain
# If bootmain returns (it shouldn't), trigger a Bochs
# breakpoint if running under Bochs, then loop.
# 在bochs中運行時用來調試用的代碼
movw $0x8a00, %ax # 0x8a00 -> port 0x8a00
movw %ax, %dx
outw %ax, %dx
movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a00
outw %ax, %dx
spin:
jmp spin
# Bootstrap GDT
.p2align 2 # force 4 byte alignment
gdt:
# 0x0000 0000 0000 0000
SEG_NULLASM # 全局描述符第0項, 8字節長的0, intel的規定
# 0x00cf 9a00 0000 ffff
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # 全局描述符第1項, 基址0, 長度4G, 代碼段
# 0x00cf 9200 0000 ffff
SEG_ASM(STA_W, 0x0, 0xffffffff) # 全局描述符第2項, 基址0, 長度4G, 數據段
gdtdesc: .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1 .long gdt # address gdt