初步学习Protected Mode(5)

来源:互联网 发布:sql语句中union 编辑:程序博客网 时间:2024/05/01 14:47

页式存储:

1、页就是一块内存。在80386中,页的大小是固定的4KB。

2、逻辑地址、线性地址、物理地址

在未打开分页机制时,线性地址等同于物理地址。逻辑地址通过分段机制直接转换成物理地址。担当分页开启时,分段机制将逻辑地址转换成线性地址,线性地址再通过分页机制转换成物理地址。

3、分页机制概述

物理地址=F(线性地址)


转换使用两级页表,第一级叫做页目录,大小为4KB。存储在一个物理页中,每个表项有4字节长,共有4096/4=1024个表项。每个表项对应第二级的一个页表,第二级的每一个页表也有1024个表项,每一个表项对应一个物理页。页目录的表项简称为PDE(Paged Directory Entry) PTE(Page Table Entry)

进行转换时,先是从cr3指定的页目录中根据线性地址的高10位得到页表地址,然后在页表中根据现行地址第12-21位得到物理页首地址,将这个首地址加上线性地址低12位便得到了物理地址。

分页机制是否生效的开关位于cr0的最高位PG位。如果PG=1,则分页机制生效。

; ==========================================; pmtest6.asm; 编译方法:nasm pmtest6.asm -o pmtest6.com; ==========================================%include"pm.inc"; 常量, 宏, 以及一些说明PageDirBaseequ200000h; 页目录开始地址:2MPageTblBaseequ201000h; 页表开始地址:2M + 4Korg0100hjmpLABEL_BEGIN[SECTION .gdt]; GDT;                                         段基址,       段界限     , 属性LABEL_GDT:Descriptor       0,                 0, 0     ; 空描述符LABEL_DESC_NORMAL:Descriptor       0,            0ffffh, DA_DRW; Normal 描述符LABEL_DESC_PAGE_DIR:Descriptor   PageDirBase,              4095, DA_DRW; Page Directory, 4KLABEL_DESC_PAGE_TBL:Descriptor   PageTblBase,              1023, DA_DRW  | DA_LIMIT_4K; Page Tables, 4MLABEL_DESC_CODE32:Descriptor       0,  SegCode32Len - 1, DA_C + DA_32; 非一致代码段, 32LABEL_DESC_CODE16:Descriptor       0,            0ffffh, DA_C; 非一致代码段, 16LABEL_DESC_DATA:Descriptor       0,DataLen - 1, DA_DRW; DataLABEL_DESC_STACK:Descriptor       0,        TopOfStack, DA_DRWA + DA_32; Stack, 32 位LABEL_DESC_VIDEO:Descriptor 0B8000h,            0ffffh, DA_DRW; 显存首地址; GDT 结束GdtLenequ$ - LABEL_GDT; GDT长度GdtPtrdwGdtLen - 1; GDT界限dd0; GDT基地址; GDT 选择子SelectorNormalequLABEL_DESC_NORMAL- LABEL_GDTSelectorPageDirequLABEL_DESC_PAGE_DIR- LABEL_GDTSelectorPageTblequLABEL_DESC_PAGE_TBL- LABEL_GDTSelectorCode32equLABEL_DESC_CODE32- LABEL_GDTSelectorCode16equLABEL_DESC_CODE16- LABEL_GDTSelectorDataequLABEL_DESC_DATA- LABEL_GDTSelectorStackequLABEL_DESC_STACK- LABEL_GDTSelectorVideoequLABEL_DESC_VIDEO- LABEL_GDT; END of [SECTION .gdt][SECTION .data1] ; 数据段ALIGN32[BITS32]LABEL_DATA:SPValueInRealModedw0; 字符串PMMessage:db"In Protect Mode now. ^-^", 0; 进入保护模式后显示此字符串OffsetPMMessageequPMMessage - $$DataLenequ$ - LABEL_DATA; END of [SECTION .data1]; 全局堆栈段[SECTION .gs]ALIGN32[BITS32]LABEL_STACK:times 512 db 0TopOfStackequ$ - LABEL_STACK - 1; END of [SECTION .gs][SECTION .s16][BITS16]LABEL_BEGIN:movax, csmovds, axmoves, axmovss, axmovsp, 0100hmov[LABEL_GO_BACK_TO_REAL+3], axmov[SPValueInRealMode], sp; 初始化 16 位代码段描述符movax, csmovzxeax, axshleax, 4addeax, LABEL_SEG_CODE16movword [LABEL_DESC_CODE16 + 2], axshreax, 16movbyte [LABEL_DESC_CODE16 + 4], almovbyte [LABEL_DESC_CODE16 + 7], ah; 初始化 32 位代码段描述符xoreax, eaxmovax, csshleax, 4addeax, LABEL_SEG_CODE32movword [LABEL_DESC_CODE32 + 2], axshreax, 16movbyte [LABEL_DESC_CODE32 + 4], almovbyte [LABEL_DESC_CODE32 + 7], ah; 初始化数据段描述符xoreax, eaxmovax, dsshleax, 4addeax, LABEL_DATAmovword [LABEL_DESC_DATA + 2], axshreax, 16movbyte [LABEL_DESC_DATA + 4], almovbyte [LABEL_DESC_DATA + 7], ah; 初始化堆栈段描述符xoreax, eaxmovax, dsshleax, 4addeax, LABEL_STACKmovword [LABEL_DESC_STACK + 2], axshreax, 16movbyte [LABEL_DESC_STACK + 4], almovbyte [LABEL_DESC_STACK + 7], ah; 为加载 GDTR 作准备xoreax, eaxmovax, dsshleax, 4addeax, LABEL_GDT; eax <- gdt 基地址movdword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址; 加载 GDTRlgdt[GdtPtr]; 关中断cli; 打开地址线A20inal, 92horal, 00000010bout92h, al; 准备切换到保护模式moveax, cr0oreax, 1movcr0, eax; 真正进入保护模式jmpdword SelectorCode32:0; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LABEL_REAL_ENTRY:; 从保护模式跳回到实模式就到了这里movax, csmovds, axmoves, axmovss, axmovsp, [SPValueInRealMode]inal, 92h; ┓andal, 11111101b; ┣ 关闭 A20 地址线out92h, al; ┛sti; 开中断movax, 4c00h; ┓int21h; ┛回到 DOS; END of [SECTION .s16][SECTION .s32]; 32 位代码段. 由实模式跳入.[BITS32]LABEL_SEG_CODE32:callSetupPagingmovax, SelectorDatamovds, ax; 数据段选择子movax, SelectorVideomovgs, ax; 视频段选择子movax, SelectorStackmovss, ax; 堆栈段选择子movesp, TopOfStack; 下面显示一个字符串movah, 0Ch; 0000: 黑底    1100: 红字xoresi, esixoredi, edimovesi, OffsetPMMessage; 源数据偏移movedi, (80 * 10 + 0) * 2; 目的数据偏移。屏幕第 10 行, 第 0 列。cld.1:lodsbtestal, aljz.2mov[gs:edi], axaddedi, 2jmp.1.2:; 显示完毕; 到此停止jmpSelectorCode16:0; 启动分页机制 --------------------------------------------------------------SetupPaging:; 为简化处理, 所有线性地址对应相等的物理地址.; 首先初始化页目录movax, SelectorPageDir; 此段首地址为 PageDirBasemoves, axmovecx, 1024; 共 1K 个表项xoredi, edixoreax, eaxmoveax, PageTblBase | PG_P  | PG_USU | PG_RWW.1:stosdaddeax, 4096; 为了简化, 所有页表在内存中是连续的.loop.1; 再初始化所有页表 (1K 个, 4M 内存空间)movax, SelectorPageTbl; 此段首地址为 PageTblBasemoves, axmovecx, 1024 * 1024; 共 1M 个页表项, 也即有 1M 个页xoredi, edixoreax, eaxmoveax, PG_P  | PG_USU | PG_RWW.2:stosdaddeax, 4096; 每一页指向 4K 的空间loop.2moveax, PageDirBasemovcr3, eaxmoveax, cr0oreax, 80000000hmovcr0, eaxjmpshort .3.3:nopret; 分页机制启动完毕 ----------------------------------------------------------SegCode32Lenequ$ - LABEL_SEG_CODE32; END of [SECTION .s32]; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式[SECTION .s16code]ALIGN32[BITS16]LABEL_SEG_CODE16:; 跳回实模式:movax, SelectorNormalmovds, axmoves, axmovfs, axmovgs, axmovss, axmoveax, cr0andal, 11111110bmovcr0, eaxLABEL_GO_BACK_TO_REAL:jmp0:LABEL_REAL_ENTRY; 段地址会在程序开始处被设置成正确的值Code16Lenequ$ - LABEL_SEG_CODE16; END of [SECTION .s16code]
在这段代码中,物理地址=F(线性地址)=线性地址



这里是PDE页目录结构和PTE页表结构:


处理器会将最近经常用到的页目录和页表项保存在TLB中,只有在TLB中找不到被请求页的转换信息时,才会到内存中寻找。当页目录或页表项被更改时,操作系统应该马上使得TLB中对应的条目无效,以便下次用到此条目时让它获得更新。当cr3被加载时,所有TLB都会总无效,除非页或页表条目的G位被设置。


cr3寄存器的结构:


cr3又叫做PDBR Page-Directory Base Register 

它的高20位将是页目录表首地址的高20位,页目录表地址的低12位会是0,也就是说,页目录表会是4KB对齐的。类似的,PDE中的页表机制和PTE中的页基址也是用高20位来表示4KB对齐的页表和页。


这份代码分页的形式如图:


不过这样分配内存,似乎太浪费了。






0 0
原创粉丝点击