首页 > 其他 > 详细

操作系统--x86分页机制

时间:2020-08-17 08:16:03      阅读:81      评论:0      收藏:0      [点我收藏+]
分页机制上
在上篇博客中可以得知对x86进行分页-需要准备页目录与页表,并且书写了一个SetupPage函数,在这里提出一个问题--如下图所示
技术分享图片
如上图所示,问题是--当call SetupPage在不同的位置的时候程序会有什么变化,同时还引出另外一个问题--进入32位保护模式代码后,应该在什么时候启动分页机制,并建立页表?
1.两个不同位置调用是不同的,第一个调用返回之后,下面所需要访问地址时需要映射,称为了虚地址,通过至此调用之后出现的问题是程序会发生变化?
通过实验结果--如下所示
技术分享图片
如图所示,发现程序并没有发生改变。
在这里对一个示例进行详细分析来解释为什么程序不会发生变化
技术分享图片
从上篇博客中可以知道1.在低12位中,表示的是页内偏移地址2.在中间10位,用于在子页表中查找目标页地址3.在最高的10位中,用于子页目录中查找页表地址
由这里的0x00804ABC可以得知ABC为低12位,代表额度是偏移地址,而中间的10位与高10又是怎样得到的?
在这里可以得知将0x00804的16进制位转换为二进制位为100000000100将其分开为10与0000000100分别对应的是2与4,说明了2的偏移量查找页目录与4的偏移量查找子页表,通过计算得出物理地址与虚地址是相等的,该结果解释了SetupPage的不同位置的调用不会影响结果。
小结论--当前的分页方式使得:任意虚地址都被直接映射为物理地址
技术分享图片
技术分享图片
实验--通过bochs下对0X00804ABC进行验证
1.首先通过反编译找到需要设置断点的地方,也就是程序跳转的地方。
技术分享图片
2.然后对其进行分析
首先可以指导0X00804ABC根据虚拟地址的计算可以得到k=2,j=4,offset=0XABC,
在这里读取内存的计算为PageDirBase 0x200000+24=0x200008,然后在bochs通过命令x /1wx 对内存进行查看,7,为什么不是4k对齐,在这里不用担心,这里的007表示的是低12为页表属性,所以应得的地址为0x00203000,接下来对PageTblBase进行计算,可得PageTblBase=0x00203000+44=0x00203000+0x10=0x00203010,通过内存查看,为0x00804007,同样的是低12为属性,这样的话地址为0x00804000,最终的物理内存为pagebase+offset=0x00804000+0xABC=0x00804ABC
技术分享图片
实验--页表映射实验
1.创建多个页表,可自由切换当前使用的页表
2.将同一个虚地址映射到不同的物理地址
3.加载不同的页表,并读取同一个虚拟地址中的内容
技术分享图片
进行该实验需要一些准备工作
1.需要创建InitPageTable函数-通过页目录地址,页表起始地址构建二级页表
2.创建SwitchPageTable函数--根据页目录起始地址切换页表,开启分页机制
代码实现

%include "inc.asm"

PageDirBase0    equ    0x200000
PageTblBase0    equ    0x201000
PageDirBase1    equ    0x300000
PageTblBase1    equ    0x301000

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_DESC0  :     Descriptor    PageDirBase0,       4095,          DA_DRW + DA_32
PAGE_TBL_DESC0  :     Descriptor    PageTblBase0,       1023,          DA_DRW + DA_LIMIT_4K + DA_32
PAGE_DIR_DESC1  :     Descriptor    PageDirBase1,       4095,          DA_DRW + DA_32
PAGE_TBL_DESC1  :     Descriptor    PageTblBase1,       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
PageDirSelector0 equ (0x0005 << 3) + SA_TIG + SA_RPL0
PageTblSelector0 equ (0x0006 << 3) + SA_TIG + SA_RPL0
PageDirSelector1 equ (0x0007 << 3) + SA_TIG + SA_RPL0
PageTblSelector1 equ (0x0008 << 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

    mov eax, PageDirSelector0
    mov ebx, PageTblSelector0
    mov ecx, PageTblBase0

    call InitPageTable

    mov eax, PageDirSelector1
    mov ebx, PageTblSelector1
    mov ecx, PageTblBase1

    call InitPageTable

    mov eax, PageDirBase0

    call SwitchPageTable

    mov eax, PageDirBase1

    call SwitchPageTable

    jmp $

; eax --> page dir base selector
; ebx --> page table base selector 
; ecx --> page table base
InitPageTable:
    push es
    push eax  ; [esp + 12]
    push ebx  ; [esp + 8]
    push ecx  ; [esp + 4]
    push edi  ; [esp]

    mov es, ax
    mov ecx, 1024    ;  1K sub page tables
    mov edi, 0
    mov eax, [esp + 4]
    or  eax, PG_P | PG_USU | PG_RWW

    cld

stdir:
    stosd
    add eax, 4096
    loop stdir

    mov ax, [esp + 8]
    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

    pop edi
    pop ecx
    pop ebx
    pop eax
    pop es

    ret   

; eax --> page directory base
SwitchPageTable:
    push eax

    mov eax, cr0
    and eax, 0x7FFFFFFF
    mov cr0, eax ;cr0最高位置0,暂时关闭分页机制

    mov eax, [esp]
    mov cr3, eax
    mov eax, cr0
    or  eax, 0x80000000
    mov cr0, eax

    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

页表切换实现
技术分享图片
在Bochs下运行的结果为
技术分享图片
可知,运行成功

操作系统--x86分页机制

原文:https://blog.51cto.com/13475106/2520729

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!