3.3.7进一步体会分页机制

来源:互联网 发布:java成神之路 编辑:程序博客网 时间:2024/06/04 19:46

 DA_C  EQU 98h ; 存在的只执行代码段属性值
DA_CR  EQU 9Ah ; 存在的可执行可读代码段属性值

LABEL_DESC_CODE32:Descriptor 0, SegCode32Len - 1, DA_CR +DA_32;把DA_C 改成DA_CR
在定义LABEL_DESC_CODE32里面把属性没有改好,结果这个错误导致DOS系统崩溃,但现在还不能理解DA_C与DA_CR的用法区别。

PS:EditPlus字体设置成Fixedys,比较符合我个人的习惯。还有要把它装在MSMA32下面才会有语法高亮

惯例附加代码:

;有三个问题,第一个是TestRead和TestWrite ,DispAL,DispReturn要放在段[SECTION .s32]里面
;  第二个问题是:显示还不能正确显示转换后的字符,为什么?
;对于NORMAL的真正作用暂时还没弄明白;
%include  "pm.inc"
;%include "lib.inc" ; 库函数 当把lib.inc的库函数放在这里是不行的,要放在SegCode32Len  的前面才可以正确显示,为什么呢?

PageDirBase0  equ 200000h ; 页目录开始地址: 2M
PageTblBase0  equ 201000h ; 页表开始地址:  2M +  4K
PageDirBase1  equ 210000h ; 页目录开始地址: 2M + 64K
PageTblBase1  equ 211000h ; 页表开始地址:  2M + 64K + 4K

LinearAddrDemo equ 00401000h
ProcFoo  equ 00401000h
ProcBar  equ 00501000h

ProcPagingDemo equ 00301000h
org 0100h
  jmp LABEL_BEGIN

[SECTION .gdt]
;GDT
LABEL_GDT:   Descriptor 0, 0, 0
LABEL_DESC_CODE32:Descriptor 0, SegCode32Len - 1, DA_CR +DA_32;把DA_C 改成DA_CR
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
LABEL_DESC_DATA: Descriptor 0, DataLen -1,DA_DRW
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32
LABEL_DESC_NORMAL:Descriptor 0, 0ffffh, DA_DRW
LABEL_DESC_CODE16:Descriptor 0, Code16Len - 1,DA_C

LABEL_DESC_PAGE_DIR: Descriptor PageDirBase, 4095, DA_DRW
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 1023, DA_DRW | DA_LIMIT_4K
;LABEL_DESC_PAGE_TBL: Descriptor   PageTblBase,      4096 * 8 - 1, DA_DRW  ; Page Tables

LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 |DA_LIMIT_4K
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_LIMIT_4K


;GDT END

PageDirBase equ 200000h;页目录开始的地址:2MB
PageTblBase equ 201000h;页表开始地址:2MB + 4KB

GdtLen equ $ -LABEL_GDT
GdtPtr dw  GdtLen - 1
   dd  0

;GDT选择子 
SelectorCode32  equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo  equ LABEL_DESC_VIDEO - LABEL_GDT
SelectorData  equ LABEL_DESC_DATA - LABEL_GDT
SelectorStack  equ LABEL_DESC_STACK - LABEL_GDT
SelectorNormal  equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode16  equ LABEL_DESC_CODE16 - LABEL_GDT

SelectorPageDir equ LABEL_DESC_PAGE_DIR -  LABEL_GDT
SelectorPageTbl equ LABEL_DESC_PAGE_TBL - LABEL_GDT

SelectorFlatC  equ LABEL_DESC_FLAT_C  - LABEL_GDT
SelectorFlatRW  equ LABEL_DESC_FLAT_RW - LABEL_GDT

;END OF [SECTION .gdt]


[SECTION .data1]
LABEL_DATA:
SPValueInRealMode dw 0
PMMessage: db "In protect mode now ^_^",0
OffsetPMMessage equ PMMessage -$$
StrTest:  db "ABCDEFGHIJKLMNOPQRSTUVWSYZ",0
OffsetStrTest equ StrTest - $$


; 实模式下使用这些符号
; 字符串
_szPMMessage:   db "In Protect Mode now. ^-^", 0Ah, 0Ah, 0 ; 进入保护模式后显示此字符串
_szMemChkTitle:   db "BaseAddrL BaseAddrH LengthLow LengthHigh   Type", 0Ah, 0 ; 进入保护模式后显示此字符串
_szRAMSize   db "RAM size:", 0
_szReturn   db 0Ah, 0
; 变量
_wSPValueInRealMode  dw 0
_dwMCRNumber:   dd 0 ; Memory Check Result
_dwDispPos:   dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。
_dwMemSize:   dd 0
_ARDStruct:   ; Address Range Descriptor Structure
 _dwBaseAddrLow:  dd 0
 _dwBaseAddrHigh: dd 0
 _dwLengthLow:  dd 0
 _dwLengthHigh:  dd 0
 _dwType:  dd 0
_PageTableNumber  dd 0

_MemChkBuf: times 256 db 0

; 保护模式下使用这些符号  地址只使用于实模式,在保护模式下,数据地址应该是其相对于段基址的偏移。
szPMMessage  equ _szPMMessage - $$
szMemChkTitle  equ _szMemChkTitle - $$
szRAMSize  equ _szRAMSize - $$
szReturn  equ _szReturn - $$
dwDispPos  equ _dwDispPos - $$
dwMemSize  equ _dwMemSize - $$
dwMCRNumber  equ _dwMCRNumber - $$
ARDStruct  equ _ARDStruct - $$
 dwBaseAddrLow equ _dwBaseAddrLow - $$
 dwBaseAddrHigh equ _dwBaseAddrHigh - $$
 dwLengthLow equ _dwLengthLow - $$
 dwLengthHigh equ _dwLengthHigh - $$
 dwType  equ _dwType  - $$
MemChkBuf  equ _MemChkBuf - $$

PageTableNumber  equ _PageTableNumber- $$

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

[SECTION .s16];漏掉了.后面的s
[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 [_wSPValueInRealMode], sp


 ;得到内存数  也应该注意这段代码的位置问题


 mov ebx, 0
 mov di, _MemChkBuf
.loop:
 mov eax, 0E820h
 mov ecx, 20
 mov edx, 0534D4150h
 int 15h
 jc  LABEL_MEM_CHK_FAIL
 add di, 20
 inc dword [_dwMCRNumber]
 cmp ebx, 0 ;放置着为等到下一个地址描述符所需要的后续值,通过它获取下一个地址范围描述符。
 ;     如果它的值为0,并且CF没有进位,表示它最后一个地址范围描述符
 jne .loop
 jmp LABEL_MEN_CHK_OK
LABEL_MEM_CHK_FAIL:
 mov dword [_dwMCRNumber], 0
LABEL_MEN_CHK_OK:

 ;初始化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
 ;Iinit code 16
 xor eax, eax
 mov ax, cs
 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
   ;Iinit STACK
 xor eax, eax
 mov ax, ss
 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
   ;Init NORMAL
  

 ;加载gdtr做准备

 

 xor eax, eax
 mov ax, ds
 shl eax, 4
 add eax, LABEL_GDT
 mov dword [GdtPtr+2], eax ;忘记+2

 lgdt [GdtPtr]

 cli

 in  al, 92h
 or  al,00000010b
 out 92h, al


 mov eax, cr0
 or  eax, 1
 mov cr0, eax


 jmp dword SelectorCode32:0

 [SECTION .s32]
 [BITS 32]

 LABEL_SEG_CODE32:
      mov ax, SelectorData
  mov ds, ax
  mov ax, SelectorData
  mov es, ax
  mov ax, SelectorVideo
  mov gs, ax
  mov ax, SelectorStack
  mov ss, ax
  mov esp, TopOfStack

  
  
  push szPMMessage
  call DispStr
  add esp, 4

  push szMemChkTitle
  call DispStr
  add esp, 4
  
  call DispMemSize
      call PagingDemo  ; 启动分页机制

  jmp SelectorCode16:0


SetupPaging:
 ; 根据内存大小计算应初始化多少PDE以及多少页表
 xor edx, edx
 mov eax, [dwMemSize]
 mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
 div ebx
 mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
 test edx, edx
 jz .no_remainder
 inc ecx  ; 如果余数不为 0 就需增加一个页表
.no_remainder:
 mov [PageTableNumber], ecx ; 暂存页表个数

 ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.

 ; 首先初始化页目录
 mov ax, SelectorFlatRW
 mov es, ax
 mov edi, PageDirBase0 ; 此段首地址为 PageDirBase0
 xor eax, eax
 mov eax, PageTblBase0 | PG_P  | PG_USU | PG_RWW
.1:
 stosd
 add eax, 4096  ; 为了简化, 所有页表在内存中是连续的.
 loop .1

 ; 再初始化所有页表
 mov eax, [PageTableNumber] ; 页表个数
 mov ebx, 1024  ; 每个页表 1024 个 PTE
 mul ebx
 mov ecx, eax  ; PTE个数 = 页表个数 * 1024
 mov edi, PageTblBase0 ; 此段首地址为 PageTblBase0
 xor eax, eax
 mov eax, PG_P  | PG_USU | PG_RWW
.2:
 stosd
 add eax, 4096  ; 每一页指向 4K 的空间
 loop .2

 mov eax, PageDirBase0
 mov cr3, eax
 mov eax, cr0
 or eax, 80000000h
 mov cr0, eax
 jmp short .3
.3:
 nop

 ret
; 分页机制启动完毕 ----------------------------------------------------------
;新增的DispMemSize
 DispMemSize:
  push esi
  push edi
  push ecx


  mov esi, MemChkBuf
  mov ecx, [dwMCRNumber]
 .loop:
  mov edx, 5
  mov edi, ARDStruct
 .1:
  push dword [esi]
  call DispInt


  pop eax
  stosd
  add esi, 4
  dec edx
  cmp edx, 0
  jnz .1
  call DispReturn
  cmp dword [dwType], 1
  jne .2
  mov eax, [dwBaseAddrLow]
  add eax, [dwLengthLow]
  cmp eax, [dwMemSize]
  jb  .2
  mov [dwMemSize], eax
 .2:
  loop .loop

  call DispReturn
  push szRAMSize
  call DispStr
  add esp, 4

  push dword [dwMemSize]
  call DispInt
  add esp, 4


  pop ecx
  pop edi
  pop esi
  ret
;********************
;PagingDemo
PagingDemo:
 mov ax, cs
 mov ds, ax
 mov ax, SelectorFlatRW
 mov es, ax


 push LenFoo
 push OffsetFoo
 push ProcFoo
 call MemCpy
 add esp, 12

 push LenBar
 push OffsetBar
 push ProcBar

 call MemCpy
 add esp, 12

 push LenPagingDemoAll
 push OffsetPagingDemoProc
 push ProcPagingDemo
 call MemCpy
 add esp, 12


 mov ax, SelectorData
 mov ds, ax
 mov es, ax

 call SetupPaging   ;启动分页
 call SelectorFlatC: ProcPagingDemo
 call PSwitch
 call SelectorFlatC: ProcPagingDemo

 ret
 ;*************************
 ;PagingDemoProc
PagingDemoProc:
OffsetPagingDemoProc  equ  PagingDemoProc  - $$
 mov eax, LinearAddrDemo
 call eax
 retf

 LenPagingDemoAll equ $ - PagingDemoProc

;******************************************
;foo
 foo:
 OffsetFoo equ  foo - $$
 mov ah, 0Ch
 mov al, 'F'
 mov [gs: ((80*17 + 0)*2)], ax
 mov al, 'o'
 mov [gs:((80*17+1)*2)], ax
 mov [gs:((80*17+2)*2)], ax

 ret

LenFoo equ $ - foo
;*******************************************
;bar
bar:
OffsetBar equ bar - $$
 mov ah, 0Ch
 mov al, 'B'
 mov [gs:((80*18+0)*2)], ax
 mov al, 'a'
 mov [gs:((80*18+1)*2)], ax
 mov al, 'r'
 mov [gs:((80*18+2)*2)], ax
 ret

LenBar equ $ - bar

;*************************************
;PSwitch
;初始化页目录
 PSwitch:
 mov ax, SelectorFlatRW
 mov es, ax
 mov edi, PageDirBase1
 xor eax, eax
 mov eax, PageTblBase1 |PG_P|PG_USU|PG_RWW
 mov ecx, [PageTableNumber] ;把eax写成了ecx
.1:
 stosd
 add eax, 4096
 loop .1

 ;初始化所有页表
 mov eax, [PageTableNumber]
 mov ebx, 1024
 mul ebx
 mov ecx, eax
 mov edi, PageTblBase1
 xor eax, eax
 mov eax, PG_P |PG_USU | PG_RWW
.2:
 stosd
 add eax, 4096
 loop .2

 mov eax, LinearAddrDemo
 shr eax, 22
 mov ebx, 4096
 mul ebx
 mov ecx, eax
 mov eax, LinearAddrDemo
 shr eax, 12
 and eax, 03FFh
 mov ebx, 4
 mul ebx
 add eax, ecx
 add eax, PageTblBase1
 mov DWORD [es:eax],ProcBar | PG_P |PG_USU | PG_RWW

 mov eax, PageDirBase1
 mov cr3, eax
 jmp short .3
.3:
 nop 
 ret

 

 

%include "lib.inc" ; 库函数

 

SegCode32Len equ  $ - LABEL_SEG_CODE32 ;上面的子程序不能放到其他位置,为什么呢?
;END OF[SECTION .S32]


 [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

 LABEL_GO_BACK_TO_REAL:
  jmp 0:LABEL_REAL_ENTRY
 Code16Len equ $ - LABEL_SEG_CODE16

[SECTION .real]
[BITS 16]
LABEL_REAL_ENTRY:
 mov ax, cs
 mov ds, ax
 mov es, ax
 mov ss, ax

 mov sp, [_wSPValueInRealMode]

 in  al, 92h
 and al, 11111101b
 out 92h, al

 sti

 mov ax, 4c00h
 int 21h
;REAL END
 ;***************