MIT6.828 BootLoader代碼分析

#include <inc/mmu.h>

;bootloader完成了16位模式的初始化,包括gdt,ds,es,ss等 , 然後進入保護模式並初始化, 然後call main.c
# Start the CPU: switch to 32-bit protected mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk into
# memory at physical address 0x7c00 and starts executing in real mode
# with %cs=0 %ip=7c00.

.set PROT_MODE_CSEG, 0x8         # kernel code segment selector 內核代碼段, .SET是給存在符號表中符號賦值的
.set PROT_MODE_DSEG, 0x10        # kernel data segment selector 內核數據段
.set CR0_PE_ON,      0x1         # protected mode enable flag 啓動保護模式標識位


; /*
; .globl _start  系統復位位置,整個程序入口
; _start是GNU彙編器的默認入口標籤,
; .globl將_start聲明爲外部程序可訪問的標籤,
; .globl是GNU彙編的保留關鍵字,前面加點是GNU彙編的語法
; */
.globl start
start:
  .code16                     # Assemble for 16-bit mode  使用 .code16 指令讓彙編器將程序彙編成 16 位的代碼
  cli                         # Disable interrupts [置中斷標識位,不可被打斷 , 相反的是STL]
  cld                         # String operations increment  
; /*
; 在計算機中,大部分數據存放在主存 中,8086CPU提供了一組處理主存中連續存放的數據串的指令——串操作指令。
; 串操作指令中,
; 源操作數用寄存器SI尋址,默認在數據段DS中,但允許段超越;目的操作數用寄存器DI尋址,默認在附加段ES中,不允許段超越。
; 每執行一次串操作指令,作爲源地址指針的SI和作爲目的地址指針的DI將自動修 改:+/-1(對於字節串)或+/-2(對於字串)。
; 地址指針是增加還是減少取決於方向標誌DF。在系統初始化後或者執行指令CLD指令後,DF=0,此時地址指針增1或2;在執行指令STD後,DF=1,此時地址指針減1或2。
; */


  # Set up the important data segment registers (DS, ES, SS). [設置數據段]
  xorw    %ax,%ax             # Segment number zero [置0]
  movw    %ax,%ds             # -> Data Segment [數據段寄存器]
  movw    %ax,%es             # -> Extra Segment [附加段寄存器]
  movw    %ax,%ss             # -> Stack Segment [棧段]

  # Enable A20:
  #   For backwards compatibility with the earliest PCs, physical
  #   address line 20 is tied low, so that addresses higher than
  #   1MB wrap around to zero by default.  This code undoes this.
  ; //開啓A20:通過將鍵盤控制器上的A20線置於高電位,全部32條地址線可用,可以訪問4G的內存空間;
seta20.1:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.1

  movb    $0xd1,%al               # 0xd1 -> port 0x64
  outb    %al,$0x64

seta20.2:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.2

  movb    $0xdf,%al               # 0xdf -> port 0x60
  outb    %al,$0x60

  # Switch from real to protected mode, using a bootstrap GDT
  # and segment translation that makes virtual addresses 
  # identical to their physical addresses, so that the 
  # effective memory map does not change during the switch.
  lgdt    gdtdesc 
  ;載入全局描述符表GDT,GDTR寄存器中保存了GDT的32位基地址和16位偏移
  ;LGDT和SGDT指令用來分別裝載和保存GDTR寄存器
  movl    %cr0, %eax
  orl     $CR0_PE_ON, %eax 
  ; 將cr0的PE置1 , 進入保護模式 
  ; cr0是控制寄存器,裏面的32個標誌位代表了控制信息 , 第0個位置PE就代表了是否開啓保護模式
  ; PE爲1代表啓動保護模式,啓動段機制;PG爲分頁機制啓動位,當PE=PG=1時,啓動分段分頁機制,地址轉換需要段處理和頁處理
  movl    %eax, %cr0
  
  # Jump to next instruction, but in 32-bit code segment.
  # Switches processor into 32-bit mode.
  ljmp    $PROT_MODE_CSEG, $protcseg

  .code32                     # Assemble for 32-bit mode [按照32位編碼]
protcseg:
  # Set up the protected-mode data segment registers 
  movw    $PROT_MODE_DSEG, %ax    # Our data segment selector
  movw    %ax, %ds                # -> DS: Data Segment
  movw    %ax, %es                # -> ES: Extra Segment
  movw    %ax, %fs                # -> FS
  movw    %ax, %gs                # -> GS
  movw    %ax, %ss                # -> SS: Stack Segment
  
  # Set up the stack pointer and call into C.
  movl    $start, %esp
  call bootmain ; 加載c代碼

  # If bootmain returns (it shouldn't), loop.
spin:
  jmp spin

# Bootstrap GDT
.p2align 2                                # force 4 byte alignment
gdt:
  SEG_NULL				# null seg 空段
  SEG(STA_X|STA_R, 0x0, 0xffffffff)	# code seg 代碼段
  SEG(STA_W, 0x0, 0xffffffff)	        # data seg 數據段

gdtdesc:
  .word   0x17                            # sizeof(gdt) - 1
  .long   gdt                             # address gdt
  ;.word就是在這個地方放一個值。相當於在這裏定義一個數據變量,用.word定義了一個16bit的數據。  .long類似

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章