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


# 开启A20

# A20地址线并不是打开保护模式的关键, 只是不开A20, 无法使用1MB以上的内存

# 因为历史原因, 在计算机启动时, 是处于实模式下, A20是关闭状态, 超出1MB内存会回卷

# 开启A20, 有三种方法,这只是其中一种

# 理论上讲, 打开A20的方法就是设置8042芯片输出端口(64h), 当该输出端口位1为1时就开启了A20信号线.

#但实际上, 当你向8042芯片输出端口进行写操作时, 在键盘缓冲区中, 或许还有别的数据尚未处理, 因此必须先处理这些数据, 这也是关中断的原因之一.


seta20.1:

#通过0x64端口, 读取8042芯片的8位状态寄存器(Status Register).
  inb     $0x64,%al     

# 当输入缓存区为空时, 状态寄存器的值就会是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



你可能感兴趣的:(XV6 - bootsect.S)