在保护模式下,控制寄存器CR0中的最高位PG位控制分页管理机制是否生效。如果PG=1,分页机制生效,把线性地址转换为物理地址。如果PG=0,分页机制无效,线性地址就直接作为物理地址。必须注意,只有在保护方式下分页机制才可能生效。只有在保证使PE位为1的前提下,才能够使PG位为1,否则将引起通用保护故障。
分页机制把线性地址空间和物理地址空间分别划分为大小相同的块。这样的块称之为页。通过在线性地址空间的页与物理地址空间的页之间建立的映射,分页机制实现线性地址到物理地址的转换。线性地址空间的页与物理地址空间的页之间的映射可根据需要而确定,可根据需要而改变。线性地址空间的任何一页,可以映射为物理地址空间中的任何一页。
采用分页管理机制实现线性地址到物理地址转换映射的主要目的是便于实现虚拟存储器。不象段的大小可变,页的大小是相等并固定的。根据程序的逻辑划分段,而根据实现虚拟存储器的方便划分页。
在80386中,页的大小固定为4K字节,每一页的边界地址必须是4K的倍数。因此,4G大小的地址空间被划分为1M个页,页的开始地址具有“XXXXX000H”的形式。为此,我们把页开始地址的高20位XXXXXH称为页码。线性地址空间页的页码也就是页开始边界线性地址的高20位;物理地址空间页的页码也就是页开始边界物理地址的高20位。可见,页码左移12位就是页的开始地址,所以页码规定了页。
由于页的大小固定为4K字节,且页的边界是4K的倍数,所以在把32位线性地址转换成32位物理地址的过程中,低12位地址保持不变。也就是说,线性地址的低12位就是物理地址的低12位。假设分页机制采用的转换映射把线性地址空间的XXXXXH页映射到物理地址空间的YYYYYH页,那么线性地址XXXXXxxxH被转换为YYYYYxxxH。因此,线性地址到物理地址的转换要解决的是线性地址空间的页到物理地址空间的页的映射,也就是线性地址高20位到物理地址高20位的转换
‘===============
<一>存储器分页管理机制
<二>线性地址到物理地址的转换
1.映射表结构
2.表项格式
页目录表或页 表的表项格式 | BIT31—BIT12 | BIT11—BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
物理页码 | AVL | 0 | 0 | D | A | 0 | 0 | U/S | R/W | P |
3.线性地址到物理地址的转换
mov eax,cr3 mov cr3,eax
4.不存在的页表
5.页的共享
<三>页级保护和虚拟存储器支持
1.页级保护
页级 保护 属性 | U/S | R/W | 用户级访问权限 | 系统级访问权限 |
0 | 0 | 无 | 读/写/执行 | |
0 | 1 | 无 | 读/写/执行 | |
1 | 0 | 读/执行 | 读/写/执行 | |
1 | 1 | 读/写/执行 | 读/写/执行 |
组合页的 保护>属性 | 目录表项U/S | 页表项U/S | 组合U/S | 目录表项R/W | 页表项R/W | 组合R/W |
0 | 0 | 0 | 0 | 0 | 0 | |
0 | 1 | 0 | 0 | 1 | 0 | |
1 | 0 | 0 | 1 | 0 | 0 | |
1 | 1 | 1 | 1 | 1 | 1 |
2.对虚拟存储器的支持
<四>页异常
出错码 的格式 | BIT15—BIT3 | BIT2 | BIT1 | BIT0 |
未使用 | U | W | P |
<五>演示分页机制的实例(实例十)
1.演示步骤和源程序清单
;名称:ASM10.ASM ;功能:演示使用分页管理机制 ;编译:TASM ASM10.ASM ;连接:TLINK ASM10.OBJ ;============================================================================ INCLUDE 386SCD.INC ;============================================================================ PDT_AD = 200000h ;页目录表所在物理页的地址 PT0_AD = 202000h ;页表0所在物理页的地址 PT1_AD = 201000h ;页表1所在物理页的地址 PhVB_AD = 0b8000h ;物理视频缓冲区地址 LoVB_AD = 0f0000h ;程序使用的逻辑视频缓冲区地址 MPVB_AD = 301000h ;线性地址0B8000H所映射的物理地址 PhSC_AD = 303000h ;部分演示代码所在内存的物理地址 LoSC_AD = 402000h ;部分演示代码的逻辑地址 ;============================================================================ GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位) ;---------------------------------------------------------------------------- ;全局描述符表GDT GDT LABEL BYTE ;空描述符 DUMMY Desc <> ;规范段描述符及选择子 Normal Desc <0ffffh,,,ATDW,,> Normal_Sel = Normal-GDT ;页目录表所在段描述符(在保护方式下初始化时用)及选择子 PDT Desc <0fffh,PDT_AD AND 0ffffh,PDT_AD SHR 16,ATDW,,> PDT_Sel = PDT-GDT ;页表0所在段描述符(在保护方式下初始化时用)及选择子 PT0 Desc <0fffh,PT0_AD AND 0ffffh,PT0_AD SHR 16,ATDW,,> PT0_Sel = PT0-GDT ;页表1所在段描述符(在保护方式下初始化时用)及选择子 PT1 Desc <0fffh,PT1_AD AND 0ffffh,PT1_AD SHR 16,ATDW,,> PT1_Sel = PT1-GDT ;逻辑视频缓冲区段描述符及选择子 LoVideo Desc <3999,LoVB_AD AND 0ffffh,LoVB_AD SHR 16,ATDW,,> LoVideo_Sel = LoVideo-GDT ;逻辑上的部分演示代码段的描述符及选择子 LoCode Desc <SCodeLen-1,LoSC_AD AND 0ffffh,LoSC_AD SHR 16,ATCE,,> LoCode_Sel = LoCode-GDT ;预定内存区域(用于部分演示代码)的段描述符及选择子 TPSCode Desc <SCodeLen-1,PhSC_AD AND 0ffffh,PhSC_AD SHR 16,ATDW,,> TPSCode_Sel = TPSCode-GDT ;---------------------------------------------------------------------------- ;以下是需额外初始化的描述符 EFFGDT LABEL BYTE ;临时代码段描述符及选择子 TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,> TempCode_Sel = TempCode-GDT ;演示代码段描述符及选择子 DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,> DemoCode_Sel = DemoCode-GDT ;演示任务数据段描述符及选择子 DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,> DemoData_Sel = DemoData-GDT ;初始化时要移动的代码段描述符及选择子(移动时作为数据对待) SCode Desc <SCodeLen-1,SCodeSeg,,ATDR,,> SCode_Sel = SCode-GDT ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表长度 GDNum = ($-EFFGDT)/(SIZE Desc) ;需特殊处理的描述符数 ;---------------------------------------------------------------------------- GDTSeg ENDS ;全局描述符表段定义结束 ;============================================================================ ;这部分代码在初始化时被复制到预定的内存区域,其功能是在屏幕上显示提示信息 ;---------------------------------------------------------------------------- SCodeSeg SEGMENT PARA USE16 ASSUME CS:SCodeSeg,DS:DemoDataSeg ;---------------------------------------------------------------------------- SBegin PROC FAR mov ax,LoVideo_Sel mov es,ax mov di,0 mov ah,17h mov cx,MessLen S1: lodsb stosw loop S1 JUMP16 DemoCode_Sel,Demo3 SBegin ENDP ;---------------------------------------------------------------------------- MLen = $-SBegin SCodeLen = $ SCodeSeg ENDS ;============================================================================ DemoDataSeg SEGMENT PARA USE16 ;演示任务数据段 Mess DB 'Page is OK!' MessLen = $-Mess DemoDataLen = $ DemoDataSeg ENDS ;============================================================================ DemoCodeSeg SEGMENT PARA USE16 ;演示任务代码段 ASSUME CS:DemoCodeSeg ;---------------------------------------------------------------------------- DemoBegin PROC FAR mov ax,PDT_Sel mov es,ax xor di,di mov cx,1024 xor eax,eax ;先把全部表项置成无效 rep stosd ;再置表项0和表项1 mov DWORD PTR es:[0],PT0_AD OR (USU+RWW+PL) mov DWORD PTR es:[4],PT1_AD OR (USU+RWW+PL) mov ax,PT0_Sel ;初始化页表0 mov es,ax xor di,di mov cx,1024 xor eax,eax or eax,USU+RWW+PL Demo1: stosd add eax,1000h ;先全部置成对应等地址的 loop Demo1 ;物理页,再特别设置两广表项 mov di,(PhVB_AD SHR 12)*4 mov DWORD PTR es:[di],MPVB_AD+USS+RWW+PL mov di,(LoVB_AD SHR 12)*4 mov DWORD PTR es:[di],PhVB_AD+USU+RWR+PL mov ax,PT1_Sel ;初始化页表1 mov es,ax xor di,di mov cx,1024 mov eax,400000h Demo2: stosd ;先把全部表项设置为无效 add eax,1000h loop Demo2 ;再特别设置1项 mov di,((LoSC_AD SHR 12)AND 3ffh)*4 mov DWORD PTR es:[di],PhSC_AD+USU+RWR+PL mov eax,PDT_AD mov cr3,eax mov eax,cr0 or eax,80000000h mov cr0,eax jmp SHORT PageE PageE: mov ax,DemoData_Sel mov ds,ax mov si,OFFSET Mess JUMP16 LoCode_Sel,SBegin Demo3: mov eax,cr0 and eax,7fffffffh ;关闭分页机制 mov cr0,eax jmp SHORT PageD PageD: mov ax,Normal_Sel JUMP16 TempCode_Sel,ToDOS DemoBegin ENDP ;---------------------------------------------------------------------------- DemoCodeLen = $ DemoCodeSeg ENDS ;============================================================================ TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段 ASSUME CS:TempCodeSeg ;---------------------------------------------------------------------------- Virtual PROC FAR cld ;为演示在启用分页机制后执 mov ax,SCode_Sel ;行位于较高线性地址空间中 mov ds,ax ;的代码作准备 mov ax,TPSCode_Sel mov es,ax mov si,OFFSET SBegin mov di,si mov cx,MLen ;把分页演示代码复制到预定 rep movsb ;内存 JUMP16 DemoCode_Sel,DemoBegin ToDOS: mov ds,ax mov es,ax mov eax,cr0 ;准备返回实模式 and al,11111110b mov cr0,eax JUMP16 <SEG Real>,<OFFSET Real> Virtual ENDP ;---------------------------------------------------------------------------- TempCodeSeg ENDS ;============================================================================ RCodeSeg SEGMENT PARA USE16 ;实方式的初始化代码和数据 ASSUME CS:RCodeSeg,DS:RCodeSeg ;---------------------------------------------------------------------------- VGDTR PDesc <GDTLen-1,> ;---------------------------------------------------------------------------- Start PROC push cs pop ds cld call InitGDT ;初始化全局描述符表GDT EnableA20 lgdt QWORD PTR VGDTR ;装载GDTR cli ;关中断 mov eax,cr0 or al,1 mov cr0,eax JUMP16 <TempCode_Sel>,<OFFSET Virtual> Real: DisableA20 sti mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- InitGDT PROC push ds mov ax,GDTSeg mov ds,ax mov cx,GDNum mov si,OFFSET EFFGDT InitG: mov ax,[si].BaseL movzx eax,ax shl eax,4 shld edx,eax,16 mov WORD PTR [si].BaseL,ax mov BYTE PTR [si].BaseM,dl mov BYTE PTR [si].BaseH,dh add si,SIZE Desc loop InitG pop ds mov bx,16 mov ax,GDTSeg mul bx mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ret InitGDT ENDP ;---------------------------------------------------------------------------- RCodeSeg ENDS END Start
2.关于实例十的说明
(1)部分演示代码的移动
(2)页映射表的初始化
(3)启动分页管理机制
mov eax,cr0 or eax,80000000h mov cr0,eax jmp SHORT PageE PageE: ...