zoukankan      html  css  js  c++  java
  • 27 x86 系统上的内存分页

     

    参考

    https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程

    一.x86系列处理器上的页式内存管理

    1.硬件层直接支持内存分页机制
    2.默认情况下不使用分页机制(段式内存管理)
    3.分页机制(进行配置)启动后,使用二级页表对内存进行管理
    x86系列处理器的分页方式(32位)
    操作系统-X86系统上的内存分页
    如图所示,32位被分成了三部分
    1.在低12位中,表示的是页内偏移地址
    2.在中间10位,用于在子页表中查找目标页地址
    3.在最高的10位中,用于子页目录中查找页表地址

    A.下面由一张图来展示分页机制

    操作系统-X86系统上的内存分页

    B.x86系列处理器的分页方式(32位)

    1.在页目录大小中,2的十次方项,每项4字节,一共为4K
    2.在子页表大小中,2的十次方项,每项4字节,一共为4K
    3.在页大小中,2的十二次方,一共为4K
    由上可以得出
    1.页目录占用1内存页-可访问1024个子页表
    2.单个子页表占用1内存页-可访问1024个页面
    3.页面起始地址按4K字节对齐-总是4096整数倍
    4.分页后可访问的虚拟内存空间为:4K(1024*1024)=4G
    X86简单的分页构建方式
    操作系统-X86系统上的内存分页
    可以通过for循环构建目录,子页表,主要原因是一个一个的生成的

    C.x86系列处理器上的页属性

    操作系统-X86系统上的内存分页
    1.由于物理页面的地址必须按照4K字节对齐
    2.由此可得,页目录可使用地址的低12位进行属性描述
    在x86系列处理器上查看页属性的说明
    操作系统-X86系统上的内存分页

    D.x86对分页的硬件支持--代码上

    如下所示
    1.将页目录起始地址放置到cr3-该寄存器类似指针指向页目录起始地址
    2.将cr0里面的值取出放置到eax寄存器中,
    3.将cr0里面的值所对应二进制最高位置1--硬件级开启分页机制
    操作系统-X86系统上的内存分页

    在这里需要注意的是

    1.loop指令-该指令表示的是循环指令

    mov ax,0
    mov cx,10
    
    Label:
                    add ax,cx
                    loop Label
    

    在这里表示是将cx减1,对cx进行判断,若cx不为0,则执行标签处Label的代码
    2.-stosb/stosw/stosd
    表示的是把al/ax/eax中的值存储到edi指向的内存单元中,同时edi的值根据方向标志增加或减少(cld/std)

    mov es,ax
    mov edi,
    mov eax,0XFF
    cld
    stosd
    

    编程实现
    loader.asm与inc.asm的设置

    %include "inc.asm"
    
    PageDirBase    equ    0x200000
    PageTblBase    equ    0x201000
    
    org 0x9000
    
    jmp ENTRY_SEGMENT
    
    [section .gdt]
    ; GDT definition
    ;                                     段基址,           段界限,       段属性
    GDT_ENTRY       :     Descriptor        0,                0,           0
    CODE32_DESC     :     Descriptor        0,        Code32SegLen - 1,    DA_C + DA_32
    VIDEO_DESC      :     Descriptor     0xB8000,         0x07FFF,         DA_DRWA + DA_32
    DATA32_DESC     :     Descriptor        0,        Data32SegLen - 1,    DA_DRW + DA_32
    STACK32_DESC    :     Descriptor        0,         TopOfStack32,       DA_DRW + DA_32
    PAGE_DIR_DESC   :     Descriptor    PageDirBase,        4095,          DA_DRW + DA_32
    PAGE_TBL_DESC   :     Descriptor    PageTblBase,        1023,          DA_DRW + DA_LIMIT_4K + DA_32
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
              
              
    ; GDT Selector
    
    Code32Selector   equ (0x0001 << 3) + SA_TIG + SA_RPL0
    VideoSelector    equ (0x0002 << 3) + SA_TIG + SA_RPL0
    Data32Selector   equ (0x0003 << 3) + SA_TIG + SA_RPL0
    Stack32Selector  equ (0x0004 << 3) + SA_TIG + SA_RPL0
    PageDirSelector  equ (0x0005 << 3) + SA_TIG + SA_RPL0
    PageTblSelector  equ (0x0006 << 3) + SA_TIG + SA_RPL0
    ; end of [section .gdt]
    
    TopOfStack16    equ 0x7c00
    
    [section .dat]
    [bits 32]
    DATA32_SEGMENT:
        DTOS               db  "D.T.OS!", 0
        DTOS_OFFSET        equ DTOS - $$
        HELLO_WORLD        db  "Hello World!", 0
        HELLO_WORLD_OFFSET equ HELLO_WORLD - $$
    
    Data32SegLen equ $ - DATA32_SEGMENT
    
    [section .s16]
    [bits 16]
    ENTRY_SEGMENT:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, TopOfStack16
        
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
        
        call InitDescItem
        
        mov esi, DATA32_SEGMENT
        mov edi, DATA32_DESC
        
        call InitDescItem
        
        mov esi, STACK32_SEGMENT
        mov edi, STACK32_DESC
        
        call InitDescItem
        
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
    
        ; 1. load GDT
        lgdt [GdtPtr]
        
        ; 2. close interrupt
        cli 
        
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
        
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
        
        ; 5. jump to 32 bits code
        jmp dword Code32Selector : 0
    
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
        
        pop eax
        
        ret
    
        
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:   
        mov ax, VideoSelector
        mov gs, ax
        
        mov ax, Stack32Selector
        mov ss, ax
        
        mov eax, TopOfStack32
        mov esp, eax
        
        mov ax, Data32Selector
        mov ds, ax
        
        mov ebp, DTOS_OFFSET
        mov bx, 0x0C
        mov dh, 12
        mov dl, 33
        
        call PrintString
        
        mov ebp, HELLO_WORLD_OFFSET
        mov bx, 0x0C
        mov dh, 13
        mov dl, 31
        
        call PrintString
        
        call SetupPage
        
        jmp $
    
    ;
    ;
    SetupPage:
        push eax
        push ecx
        push edi
        push es
        
        mov ax, PageDirSelector
        mov es, ax
        mov ecx, 1024    ;  1K sub page tables
        mov edi, 0
        mov eax, PageTblBase | PG_P | PG_USU | PG_RWW
        
        cld
        
    stdir:
        stosd
        add eax, 4096
        loop stdir
        
        mov ax, PageTblSelector
        mov es, ax
        mov ecx, 1024 * 1024   ; 1M pages
        mov edi, 0
        mov eax, PG_P | PG_USU | PG_RWW
        
        cld
        
    sttbl:
        stosd
        add eax, 4096
        loop sttbl
        
        mov eax, PageDirBase
        mov cr3, eax
        mov eax, cr0
        or  eax, 0x80000000
        mov cr0, eax
        
        pop es
        pop edi
        pop ecx
        pop eax
        
        ret   
    
    ; ds:ebp    --> string address
    ; bx        --> attribute
    ; dx        --> dh : row, dl : col
    PrintString:
        push ebp
        push eax
        push edi
        push cx
        push dx
        
    print:
        mov cl, [ds:ebp]
        cmp cl, 0
        je end
        mov eax, 80
        mul dh
        add al, dl
        shl eax, 1
        mov edi, eax
        mov ah, bl
        mov al, cl
        mov [gs:edi], ax
        inc ebp
        inc dl
        jmp print
    
    end:
        pop dx
        pop cx
        pop edi
        pop eax
        pop ebp
        
        ret
        
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    [section .gs]
    [bits 32]
    STACK32_SEGMENT:
        times 1024 * 4 db 0
        
    Stack32SegLen equ $ - STACK32_SEGMENT
    TopOfStack32  equ Stack32SegLen - 1
    
    ; Segment Attribute
    DA_32       equ    0x4000
    DA_LIMIT_4K    EQU       0x8000
    DA_DR       equ    0x90
    DA_DRW      equ    0x92
    DA_DRWA     equ    0x93
    DA_C        equ    0x98
    DA_CR       equ    0x9A
    DA_CCO      equ    0x9C
    DA_CCOR     equ    0x9E
    
    ; Segment Privilege
    DA_DPL0        equ      0x00    ; DPL = 0
    DA_DPL1        equ      0x20    ; DPL = 1
    DA_DPL2        equ      0x40    ; DPL = 2
    DA_DPL3        equ      0x60    ; DPL = 3
    
    ; Special Attribute
    DA_LDT       equ    0x82
    DA_TaskGate  equ    0x85    ; 任务门类型值
    DA_386TSS    equ    0x89    ; 可用 386 任务状态段类型值
    DA_386CGate  equ    0x8C    ; 386 调用门类型值
    DA_386IGate  equ    0x8E    ; 386 中断门类型值
    DA_386TGate  equ    0x8F    ; 386 陷阱门类型值
    
    ; Selector Attribute
    SA_RPL0    equ    0
    SA_RPL1    equ    1
    SA_RPL2    equ    2
    SA_RPL3    equ    3
    
    SA_TIG    equ    0
    SA_TIL    equ    4
    
    PG_P    equ    1    ; 页存在属性位
    PG_RWR  equ    0    ; R/W 属性位值, 读/执行
    PG_RWW  equ    2    ; R/W 属性位值, 读/写/执行
    PG_USS  equ    0    ; U/S 属性位值, 系统级
    PG_USU  equ    4    ; U/S 属性位值, 用户级
    
    ; 描述符
    ; usage: Descriptor Base, Limit, Attr
    ;        Base:  dd
    ;        Limit: dd (low 20 bits available)
    ;        Attr:  dw (lower 4 bits of higher byte are always 0)
    %macro Descriptor 3                              ; 段基址, 段界限, 段属性
        dw    %2 & 0xFFFF                         ; 段界限1
        dw    %1 & 0xFFFF                         ; 段基址1
        db    (%1 >> 16) & 0xFF                   ; 段基址2
        dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
        db    (%1 >> 24) & 0xFF                   ; 段基址3
    %endmacro                                     ; 共 8 字节
    
    ; 门
    ; usage: Gate Selector, Offset, DCount, Attr
    ;        Selector:  dw
    ;        Offset:    dd
    ;        DCount:    db
    ;        Attr:      db
    %macro Gate 4
        dw    (%2 & 0xFFFF)                      ; 偏移地址1
        dw    %1                                 ; 选择子
        dw    (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
        dw    ((%2 >> 16) & 0xFFFF)              ; 偏移地址2
    %endmacro 
    

    设置的过程如下图所示
    操作系统-X86系统上的内存分页操作系统-X86系统上的内存分页操作系统-X86系统上的内存分页操作系统-X86系统上的内存分页
    通过make之后得到的结果
    操作系统-X86系统上的内存分页
    操作系统-X86系统上的内存分页
    在这里的打印结果为字符串,并没有分页的显示效果,在后面的博客会对该次实验进行解释 

    小结

    1.x86处理器直接支持内存分页机制
    2.分页机制启动后,使用二级页表对内存进行管理
    3.页目录和单个子页表占用1内存页
    4.页面起始地址按4K字节对齐
    5.分页后可访问的虚拟内存空间为4G

     

      

      

      

  • 相关阅读:
    换零钞
    空心菱形
    生成回文数
    机器人数目
    胡同门牌号
    七星填数
    阶乘位数
    打印数字
    平方末尾
    数位和
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14250003.html
Copyright © 2011-2022 走看看