#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類似