; boot.asm
bits 16
start16:
mov ax, 0x7c0 ;實模式下,數據段、堆棧段基地址都爲0x7c00
mov ds, ax
mov ss, ax
mov sp, 0x0
cli ;應關閉中斷
; 讀取硬盤第二個扇區到內存0x7e00處, 是緊挨着引導扇區內存處的一個扇區
mov dx, 0x1f2
mov al, 2 ;一下加載了兩個扇區,因此,下面的向緩衝區中寫入數據也應該是,一個扇區的兩倍
out dx, al
mov dx, 0x1f3
mov al, 1 ;第二個扇區,邏輯扇區從0開始計數。這也是容易出問題的地方
out dx, al
mov dx, 0x1f4
mov al, 0
out dx, al
mov dx, 0x1f5
mov al, 0
out dx, al
mov dx, 0x1f6
mov al, 0xe0 ;第一塊硬盤,LBA模式
out dx, al
mov dx, 0x1f7
mov al, 0x20 ;讀命令
out dx, al
mov dx, 0x1f7
.1:
in al, dx
and al, 0x88
cmp al, 0x08 ;測試是否完成操作
jnz .1
mov bx, 0x200 ; 0x7c00 + 0x200,512 bytes,即0x7e00
mov dx, 0x1f0
mov cx, 2 * 256
.2:
in ax, dx
mov [bx], ax
inc bx
inc bx
loop .2
lgdt [gdtr]
;open A20 address line
in al, 0x92
or al, 0x2
out 0x92, al
;set CR0 protected mode bit
mov eax, cr0
or al, 0x1
mov cr0, eax
jmp dword 1 * 8 : 0 ;更新cs,eip
gdtr:
dw gdt_end - gdt_start - 1; global descriptor table size -- xxx bytes
dd gdt_start + 0x7c00; phy Address
gdt_start:
dq 0x0000000000000000 ; 0 * 8
dq 0x00c09a007e00ffff ; 1 * 8 segment base address 0x7c00 + 0x200
dq 0x00c092007e00ffff ; 2 * 8
dq 0x00c0920b8000ffff ; 3 * 8 video memory address
dq 0x00c092100000ffff ; 4 * 8 other data segment
dq 0x000092000000ffff ; 5 * 8 other data segment
dq 0x000098000000ffff ; 6 * 8 other data segment
gdt_end:
times 512 - 2 - ($ - $$) db 0
dw 0xaa55 ; == db 0x55, 0xaa
;loader.asm
bits 32
start:
mov ax, 2 * 8
mov ds, ax
mov ax, 3 * 8
mov es, ax
mov ebx, 3 * 160
mov byte [es: ebx], 'l'
inc ebx
mov byte [es: ebx], 0xc
inc ebx
jmp 6 * 8 : 0x7e00 + start16 ;這裏《orange's一個操作系統的實現》說是應該切換到16位代碼段
;但古老的清華書似乎沒有這麼說,但是還是這樣做了
;決定明天按照清華老書裏直接切換到實模式,驗證一下,到底誰的對。
jmp $
align 32
bits 16
start16:
mov ax, 5 * 8
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
;位0清零後,切換到實模式,緊接着就要刷新高速緩存,從而進入實模式
mov eax, cr0
and eax, 1111_1111_1111_1110b
mov cr0, eax
;這段顯示字符的程序一定要在保護模式位清零後,方可執行,否則宕機
xor bx, bx
mov ax, 0xb800
mov es, ax
mov byte [es: bx], 'a'
inc bx
mov byte [es: bx], 0xe
inc bx
;這裏使用db僞指令定義的跳轉到實模式的代碼段的指令,nasm應該怎麼表示,我不太知道
;明天也要驗證一下這裏,看看nasm的jmp指令是否也生成同樣的機器碼。
db 0xea
dw 0x8000
dw 0
; kernel.asm
bits 16
start16:
mov ax, 0
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0
;應該關閉a20地址線
in al, 0x92
and al, 1111_1101b
out 0x92, al
mov bx, 160
mov ax, 0xb800
mov es, ax
mov byte [es: bx], 'r'
inc bx
mov byte [es: bx], 0xa
inc bx
;一定要打開中斷,否則沒法用BIOS中斷讀軟盤引導扇區到0x7c00處。
sti
mov dx, 0
mov cx, 1
mov ax, 0x7c0
mov es, ax
mov bx, 0
mov ax, 0x201
int 0x13
jmp 0x7c0 : 0 ;跳轉到軟盤的引導扇區,我們的系統是用硬盤引導扇區加載的。
;軟盤裏面預製的是menuetOS,一個純粹用彙編語言寫成的操作系統。這樣就完成王爽老師大作業中的一個小知識點。