pmtest6.asm代码详细解释,对分页的形成过程有详细的解释
; ==========================================
; 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,PageDirBase=2000000h
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 1023, DA_DRW | DA_LIMIT_4K ; Page Tables, 4M,PageTblBase=201000h
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 [LABEL_DESC_CODE16 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE16 + 4], al
mov byte [LABEL_DESC_CODE16 + 7], ah
; 初始化 32 位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
; 初始化数据段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_DATA
mov word [LABEL_DESC_DATA + 2], ax
shr eax, 16
mov byte [LABEL_DESC_DATA + 4], al
mov byte [LABEL_DESC_DATA + 7], ah
; 初始化堆栈段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_STACK
mov word [LABEL_DESC_STACK + 2], ax
shr eax, 16
mov byte [LABEL_DESC_STACK + 4], al
mov byte [LABEL_DESC_STACK + 7], ah
; 为加载 GDTR 作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ; eax <- gdt 基地址
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
; 加载 GDTR
lgdt [GdtPtr]
; 关中断
cli
; 打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al
; 准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
; 真正进入保护模式
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, [SPValueInRealMode]
in al, 92h ; ┓
and al, 11111101b ; ┣ 关闭 A20 地址线
out 92h, al ; ┛
sti ; 开中断
mov ax, 4c00h ; ┓
int 21h ; ┛回到 DOS
; END of [SECTION .s16]
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
LABEL_SEG_CODE32:
call SetupPaging //启动分页机制
mov ax, SelectorData
mov ds, ax ; 数据段选择子
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子
mov ax, SelectorStack
mov ss, ax ; 堆栈段选择子
mov esp, TopOfStack
; 下面显示一个字符串
mov ah, 0Ch ; 0000: 黑底 1100: 红字
xor esi, esi
xor edi, edi
mov esi, OffsetPMMessage ; 源数据偏移
mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。
cld
.1:
lodsb
test al, al
jz .2
mov [gs:edi], ax
add edi, 2
jmp .1
.2: ; 显示完毕
; 到此停止
jmp SelectorCode16:0
; 启动分页机制 --------------------------------------------------------------
SetupPaging:
; 为简化处理, 所有线性地址对应相等的物理地址.
; 首先初始化页目录
mov ax, SelectorPageDir ; 此段首地址为 PageDirBase //PageDirBase=200000h
mov es, ax //es指向PageDirBase,页目录基址
mov ecx, 1024 ; 共 1K 个表项
xor edi, edi
xor eax, eax
mov eax, PageTblBase | PG_P | PG_USU | PG_RWW //PageTblBase=201000h,将PageTblBase加属性的结果赋给eax。eax值通过stosd放到
.1: // es:edi指向的地址处,即页目录基址处。
stosd //stosd的作用是将累加器EAX内容存储到由ES:E(DI)寻址的内存地址,d表示是32位
add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. //eax中的PageTblBase的基址加4096,并通过循环不断加4096.
loop .1
; 再初始化所有页表 (1K 个, 4M 内存空间)
mov ax, SelectorPageTbl ; 此段首地址为 PageTblBase
mov es, ax
mov ecx, 1024 * 1024 ; 共 1M 个页表项, 也即有 1M 个页
xor edi, edi
xor eax, eax
mov eax, PG_P | PG_USU | PG_RWW
.2:
stosd
add eax, 4096 ; 每一页指向 4K 的空间
loop .2
mov eax, PageDirBase //将页目录基址赋给eax,再由eax赋给cr3
mov cr3, eax //把PageDirBase页目录基地址赋给cr3
mov eax, cr0
or eax, 80000000h
mov cr0, eax
jmp short .3
.3:
nop
ret
; 分页机制启动完毕 ----------------------------------------------------------
SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
; 跳回实模式:
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, 11111110b
mov cr0, eax // PE=0, PG=0关闭分页,进入实模式
LABEL_GO_BACK_TO_REAL:
jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值
Code16Len equ $ - LABEL_SEG_CODE16
; END of [SECTION .s16code]
----------------------------------------------------------------------------------------
启动分页部分程序的结果为:
1、 在物理内存页目录基址200000H处 存放了1024个PDE的结合
- PDE1(PageTblBase 201000H+0000H )---->这是一个PDE的一部分,因为PTE的基址就放在一个PDE
- PDE2( 201000H+1000H)
- PDE3( 201000H+2000H)
- 。。。。。。。。
- PDE1024( 201000H+3FF000H)以上一共1024个PDE ,一个PDE大小为4字节(4Bety),一共为4K,这样所有PDE就初始化好了。
页目录构建好之后,正好到物理内存的201000H处,这也是第一个页表的基址
2、在物理内存页表基址201000H处 存放了1024*1024个PTE
- PTE1(PageBase 0000H) 这是第一个页表基址201000H所对应的1024个PTE ,存放一个页表的物理的大小是4K。4Byte*1024=4K字节。
- PTE2( 0000H+1000H) 每个PTE对应的页的真实物理大小为4K,范围是从0000H---0FFFH,所以偏移地址要加1000H,一个PTE本身是4个字节,4Bety
- PTE3( 0000H+2000H)
- PTE2( 0000H+3000H)
- PTE2( 0000H+4000H)
- ........
- PTE1024( 0000H+3FF000H) 以上这些PTE一共表示了4M大小的的真实物理内存 0000H~~3FF000H正好是4M
----------------------------------------------------------
- PTE1025( 0000H+400000H) 这是第二个页表基址201000H+1000H所对应的1024个PTE,大小为4k
- PTE1026( 0000H+401000H)
- PTE1027( 0000H+402000H)
- .......
- PTE2048( 0000H+7FF000H)
----------------------------------------------------------
。
。
。
———————————————————————————————
- PTE1024*1024-1023(0000H+FFC00000H)这是第1024个页表基址201000H+3FF000H所对应的1024个PTE,大小为4K
- .......
- PTE1024*1024 (0000H+FFFFF000H) // FFC00+3FF=FFFFF
最后一个page base address FFFFF000H对应一个page ,大小为0~FFFh,加上基址正好是FFFFFFFFH,所以一共4G物理内存都被PTE分配了。
----------------------------------------------------------
以上一共有1024*1024个PTE,一个PTE为4bety,一共是4M。
页表建构好之后201000+4M=601000
所以PDE,PTE都建构好之后,它的地址为200000H到601000H。
posted on 2011-04-26 13:51 wanghj_dz 阅读(1034) 评论(0) 编辑 收藏 举报