6.828 操作系統(tǒng) lab1: 閱讀boot.S

補充知識


補充1. AT&T匯編

由于內(nèi)核代碼采用的gcc編譯器使用AT&T的匯編格式,首先補充下關(guān)于AT&T匯編的知識。

  • 匯編器命令 (assembler directives)
  • 匯編程序中以.開頭的不會被翻譯成機器指令,而是給編譯器一些特殊的指示。
  • 操作數(shù)賦值方向
    • 從左到右。
  • 前綴
    • 寄存器前綴為%,立即數(shù)前綴為$ 。
  • 后綴
    • 指令最后一個字符用于表示操作數(shù)的大小,b表示byte(1個字節(jié)),w表示word(2個字節(jié)),l表示long(4個字節(jié))。

補充2. A20門和PS/2 Controller

在 8086 中有 20 根地址總線,通過 CS:IP 對的方式尋址,最大訪問地址為 1MB,然而,F(xiàn)FFFH:FFFFH = 10FFEFH,也就是說從 100000H 到 10FFEFH 無法訪問,當訪問這段地址時,會產(chǎn)生 wrap-around,也就是實際訪問地址會對 1MB 求模。
到了 80286 中有 24 根地址總線,最大訪問地址為 16MB。這個時候,不會產(chǎn)生 wrap-around,為了向下兼容 8086,需要使用第 21 根地址總線。
所以 IBM 的工程師使用 PS/2 Controller 輸出端口中多余的端口來管理 A20 gate,也就是第 21 根地址總線(從 0 開始)。
注意下表,0x60用于讀寫數(shù)據(jù),0x64用于讀寫狀態(tài)。

PS/2 Controller IO Ports

IO Port Access Type Purpose
0x60 Read/Write Data Port
0x64 Read State Register
0x64 Write Command Register

Status Register

Bit Meaning
1 Input buffer status (0 = empty, 1 = full)
(must be clear before attempting to write data to IO port 0x60 or IO port 0x64)

Command Register

Command Byte Meaning Response
0xD1 Write next byte to Controller Output Port
Note: Check if output buffer is empty first
None

PS/2 Controller Output Port

Bit Meaning
1 A20 gate (output)

boot.S

boot/boot.S可以分為兩部分,第一部分是在實模式下運行的。

#include <inc/mmu.h>

# 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 相當于 #define,用于設(shè)置常量
.set PROT_MODE_CSEG, 0x8         # kernel code segment selector
.set PROT_MODE_DSEG, 0x10        # kernel data segment selector
.set CR0_PE_ON,      0x1         # protected mode enable flag


# .globl使得連接程序(ld)能夠看到start。
# 作用是使得同一文件夾的其他文件能引用start。
.globl start
start:
  .code16                     # Assemble for 16-bit mode
  cli                         # Disable interrupts
  cld                         # String operations increment

  # Set up the important data segment registers (DS, ES, SS).
  # AX, DS, ES, SS 寄存器全部置0
  xorw    %ax,%ax             # Segment number zero
  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.
  
  # 從PS/2 Controller的I/O Port讀取一個byte
  # **** **1* 表示忙, 所以用0x2作test運算
  # 若test結(jié)果不為0, jnz跳轉(zhuǎn)回函數(shù)起點
seta20.1:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.1
  # 通知PS/2 Controller,將下一個寫入0x60的字節(jié)寫出到 Output Port
  movb    $0xd1,%al               # 0xd1 -> port 0x64
  outb    %al,$0x64

  # 與seta20.1作用相同,等待端口空閑
seta20.2:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.2
  # 將0xdf寫出到0x60, 再寫出到 Output Port, 打開了A20 gate 
  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
  movl    %cr0, %eax
  orl     $CR0_PE_ON, %eax
  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
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

  # 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容