XV6 - bootsect.S

#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 Segment
oop


# 開啓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

相關文章
相關標籤/搜索