[OS64位][017]源码阅读:代码清单3-28~3-37 保护模式 -> IA-32e模式 (开启分页)

学习笔记

使用教材(配书源码以及使用方法)
《一个64位操作系统的设计与实现》
http://www.ituring.com.cn/book/2450
https://www.jianshu.com/p/28f9713a9171

源码文件

  • 第3章\程序\程序3-4\ loader.asm

源码阅读:保护模式 -> IA-32e模式(或称长模式)

代码清单3-28 Line 42 ~ 53 : IA-32e模式的段结构

代码清单3-29 Line 495~513 : GO_TO_TMP_Protect
(在代码清单3-27执行后继续执行)
代码清单3-30 Line 574~595 : test support long mode or not

代码清单3-31 Line 514~532 : init template page table 0x90000

代码清单3-32 Line 533~545 : load GDTR
代码清单3-33 Line 546~551 : open PAE
代码清单3-34 Line 552~556 : load cr3
代码清单3-35 Line 557~564 : enable long-mode
代码清单3-36 Line 565~570 : open PE and paging
代码清单3-37 Line 572 : 从Loader跳转到内核程序
[SECTION gdt64]

LABEL_GDT64:        dq  0x0000000000000000
LABEL_DESC_CODE64:  dq  0x0020980000000000
LABEL_DESC_DATA64:  dq  0x0000920000000000

GdtLen64    equ $ - LABEL_GDT64
GdtPtr64    dw  GdtLen64 - 1
        dd  LABEL_GDT64

SelectorCode64  equ LABEL_DESC_CODE64 - LABEL_GDT64
SelectorData64  equ LABEL_DESC_DATA64 - LABEL_GDT64
[SECTION .s32]
[BITS 32]

GO_TO_TMP_Protect:

;=======    go to tmp long mode

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov ss, ax
    mov esp,    7E00h

    call    support_long_mode
    test    eax,    eax

    jz  no_support

;=======    init temporary page table 0x90000

    mov dword   [0x90000],  0x91007
    mov dword   [0x90800],  0x91007     

    mov dword   [0x91000],  0x92007

    mov dword   [0x92000],  0x000083

    mov dword   [0x92008],  0x200083

    mov dword   [0x92010],  0x400083

    mov dword   [0x92018],  0x600083

    mov dword   [0x92020],  0x800083

    mov dword   [0x92028],  0xa00083

;=======    load GDTR

    db  0x66
    lgdt    [GdtPtr64]
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov esp,    7E00h

;=======    open PAE

    mov eax,    cr4
    bts eax,    5
    mov cr4,    eax

;=======    load    cr3

    mov eax,    0x90000
    mov cr3,    eax

;=======    enable long-mode

    mov ecx,    0C0000080h      ;IA32_EFER
    rdmsr

    bts eax,    8
    wrmsr

;=======    open PE and paging

    mov eax,    cr0
    bts eax,    0
    bts eax,    31
    mov cr0,    eax


    jmp SelectorCode64:OffsetOfKernelFile

;=======    test support long mode or not

support_long_mode:

    mov eax,    0x80000000
    cpuid
    cmp eax,    0x80000001
    setnb   al  
    jb  support_long_mode_done
    mov eax,    0x80000001
    cpuid
    bt  edx,    29
    setc    al
support_long_mode_done:
    
    movzx   eax,    al
    ret

;=======    no support

no_support:
    jmp $
OffsetOfKernelFile  equ 0x100000

关于IA-32e模式

  • IA-32e模式简化了保护模式的段结构,删减掉冗余的段基地址和段限长,使段直接覆盖整个线性地址空间,进而变成平坦地址空间

  • 一旦激活IA-32e模式,软件便可重定位页表物理内存空间的任何地方

  • CR4控制寄存器的第5位PAE功能的标志位,置位该标志位可开启PAE(开启物理地址扩展功能)

  • 加载页目录基地址CR3控制寄存器

  • mov cr0, eax ,至此,处理器进入IA-32e模式

  • 需要一条跨段跳转/调用指令将CS段寄存器的值更新为IA-32e模式的代码段描述符 jmp SelectorCode64:OffsetOfKernelFile

进入IA-32e模式

参考资料

  • 使用到的寄存器
    https://wiki.osdev.org/CPU_Registers_x86-64#CR0
CR0
CR4
IA32_EFER
  • 关于平坦模式

在平坦模式下,名义上不分段,但实际上是只分一个大段,在这种情况下,不管程序实际加载到哪里,代码段、数据段和栈段,其描述符的基地址都固定为0x00000000

你可能感兴趣的:([OS64位][017]源码阅读:代码清单3-28~3-37 保护模式 -> IA-32e模式 (开启分页))