一 页式存储
1 概念
所谓页就是一块内存,在80386中页的大小是4K,在奔腾中页的大小是2M或者4M 。
2 逻辑地址 、 线性地址、物理地址
在未打开分页机制前,线性地址等同于物理地址。可以认为,逻辑地址通过分段机制转换成线性地址。但当分页机制
开启时,逻辑地址先通过分段机制转换成线性地址,然后线性地址通过分页机制转换成物理地址。实现分页机制,主要是
实现虚拟存储器。
3 分页数据结构
转换采用两级页表,第一级叫做页目录,大小是4KB ,存储在一个物理页中,每个页表项大小是4KB 。每个页表项
对应第二级的一个页表,第二级的每一个页表也有1024个表项,每一个表项对用每一个物理页。页目录的表项简称为PDE
(page Directory entry) ,页表的表项简称为PTE(page Table Entry) 。
进行转换时,先是从寄存器CR3指定的页目录中根据线性地址的高10位得到页表地址,然后在页表中根据线性地址的
12-21位,将这个首地址加上线性地址的低12位,就得到了物理地址。 10 位bit可以表示1024个选择,页目录中有1024改个目录项,则根据线性地址的高10位,就可以判断是哪个目录项,然后目录项中存储了页表的首地址。得到了页表的首地址
分页机制是否有效的开关CR0的最高位PG位,如果分页有效那么PG位为1 。所以当我们设置好了 页目录表和页表,并
将CR3寄存器指向页目录表之后,只需要设置PG位,然后分页机制开始工作。
4 CR3 寄存器
指向页目录的首地址,它的高20位是页目录表首地址的高20位,页目录表的低地址位会是0 ,也就是说页目录表是4KB
对齐的。
5 程序代码
; ==========================================
; pmtest6.asm
; 编译方法:nasm pmtest6.asm -o pmtest6.com
; ==========================================
%include "pm.inc" ; 常量, 宏, 以及一些说明
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
org 0100h
jmp LABEL_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, 4K
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 1023, DA_DRW | DA_LIMIT_4K ; Page Tables, 4M
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段, 16
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32 ; Stack, 32 位
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
; GDT 结束
GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址
; GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorPageDir equ LABEL_DESC_PAGE_DIR - LABEL_GDT
SelectorPageTbl equ LABEL_DESC_PAGE_TBL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
[SECTION .data1] ; 数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode dw 0
; 字符串
PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串
OffsetPMMessage equ PMMessage - $$
DataLen equ $ - LABEL_DATA
; END of [SECTION .data1]
; 全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
; END of [SECTION .gs]
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h
mov [LABEL_GO_BACK_TO_REAL+3], ax
mov [SPValueInRealMode], sp
; 初始化 16 位代码段描述符
mov ax, cs
movzx eax, ax
shl eax, 4
add eax, LABEL_SEG_CODE16
mov word [LABE