bootloader進入保護模式的過程

%cs=0 $pc=0x7c00,bootloader的首地址進入後

首先清理環境:包括將flag置0和將段寄存器置0

    .code16
        cli
        cld
        xorw %ax, %ax
        movw %ax, %ds
        movw %ax, %es
        movw %ax, %ss

開啓A20:通過將鍵盤控制器上的A20線置於高電位,全部32條地址線可用, 可以訪問4G的內存空間。

爲什麼是A20呢?這是一個歷史問題。8086是用SEG:OFFSET這樣的模式分段的,所以,它能表示的最大內存是FFFF:FFFF,即10FFEFh。但8086只有20位的地址總線,智能尋址到1MB,如果試圖訪問超過1MB的地址會回捲(wrap),就是重新從地址零開始尋址。而到了80386時,就可以訪問1MB以上的內存了,就不會再回卷,需要向上兼容,使用8042鍵盤控制器來控制第20個(從零開始數)地址位,這就是A20地址線,如果不被打開,第20個地址爲將會總是零。

所以爲了訪問所有的內存,需要開啓A20,開機時它默認是關閉的。

    seta20.1:               # 等待8042鍵盤控制器不忙
        inb $0x64, %al      # 
        testb $0x2, %al     #
        jnz seta20.1        #
    
        movb $0xd1, %al     # 發送寫8042輸出端口的指令
        outb %al, $0x64     #
    
    seta20.1:               # 等待8042鍵盤控制器不忙
        inb $0x64, %al      # 
        testb $0x2, %al     #
        jnz seta20.1        #
    
        movb $0xdf, %al     # 打開A20
        outb %al, $0x60     # 

初始化GDT表:將gdtdesc指示的6字節加載到寄存器gdtr,一個簡單的GDT表和其描述符已經靜態儲存在引導區中,載入即可。

        lgdt gdtdesc

進入保護模式:通過將cr0寄存器PE位置1便開啓了保護模式

        movl %cr0, %eax
        orl $CR0_PE_ON, %eax
        movl %eax, %cr0

通過長跳轉更新cs的基地址(進入32位保護模式)

     ljmp $PROT_MODE_CSEG, $protcseg
    .code32
    protcseg:

設置段寄存器,並建立堆棧

        movw $PROT_MODE_DSEG, %ax
        movw %ax, %ds
        movw %ax, %es
        movw %ax, %fs
        movw %ax, %gs
        movw %ax, %ss
        movl $0x0, %ebp
        movl $start, %esp

轉到保護模式完成,進入boot主方法

        call bootmain

 

 

Q:在實模式下,16位的寄存器(8086)需要用到 “SEG:OFFSET”這種方法才能達到1MB的尋址能力,現在我們有32位寄存器(80386),尋址空間達到了4GB,是否此段值就被拋棄了?

A:沒有,在32位中仍然用“SEG:OFFSET”的形式來表示,只不過保護模式下“段”的概念發生了根本性的變化。實模式下,段值可以看作是地址的一部分,段值爲XXXXh表示以XXXX0h開始的一段內存。而保護模式下,如果段值仍然由原來16位的cs、ds等寄存器表示,但此時它僅僅變成了一個索引,這個索引指向一個GDT的數據結構的表項(描述符),表項中詳細定義了段的起始地址、界限、屬性等內容。

 

 

關於“保護模式”的幾點理解:

 

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