pmtest7.asm

1.如何由内存推出页表数量
假设内存空间为32MB, 由于每个页是4KB, 则我们需要8K个页表,而每个页表实际占4个字节,所以一共是页表所占内存为32KB

这里写图片描述

分配内存依然是从零开始的,但是里面有一些内存是不能用的,我们只能说自己线性地址指向的内存有部分可用,可用的最大值的地址是01FF0000h, 所以说可以用的内存都被指向到了

;======================================
;pmtest7.asm
;编译方法:nasm pmtest7.asm -o pmtest7.bin
;======================================
%include "pm.inc";  常量,宏 以及一些说明
;org 07c00h

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, 4096*8-1, DA_DRW        ;32KB的页表   
LABEL_DESC_CODE32:  Descriptor  0,  SegCode32Len - 1, DA_C + DA_32;  非一致代码段
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C;  
LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32;   
LABEL_DESC_VIDEO : Descriptor 0B8000h, 0ffffh, DA_DRW;  显存首地址
;GDT 就是一个数组结构

GdtLen  equ  $-LABEL_GDT  ;GDT长度
GdtPtr  dw   GdtLen - 1  ;GDT 界限
    dd 0  ; GDT基地址
;GdtPtr也是一个数据结构  前2字节是GDT界限  后4字节是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:

;实模式下使用这些符号
;字符串

_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

_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	- $$

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]



;这是一个16位代码段 这个程序修改了gdt中的一些值 然后执行跳转到第三个section
[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     [_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  ;CF=1  发生了错误
    add di, 20
    inc dword [_dwMCRNumber]  ;_dwMCRNumber每次循环加一  作为循环次数
    cmp ebx, 0
    jne .loop
    jmp LABEL_MEM_CHK_OK
LABEL_MEM_CHK_FAIL:
    mov dword [_dwMCRNumber], 0  ;循环次数清零
LABEL_MEM_CHK_OK:


    ;初始化16位的代码段描述符
    mov ax, cs
    movzx   eax, ax

;   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

    ;初始化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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LABEL_REAL_ENTRY:   ;从保护模式跳回到实模式就到了这里
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax

    mov     sp, [_wSPValueInRealMode]   ;指针调到了堆栈中  返回到实模式

    in  al, 92h
    and al, 11111101b;  关闭A20地址线
    out 92h, al

    sti;  开中断

    mov ax, 4c00h;
    int 21h;    回到dos
;end of section .s16




[SECTION .s32]
[BITS 32]

LABEL_SEG_CODE32:
    ;call   SetupPaging

    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    SetupPaging     ; 启动分页机制

    ; 到此停止
    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    ; 测试edx 是否为空 edx是放余数的位置
    jz  .no_remainder
    inc ecx     ; 如果余数不为 0 就需增加一个页表
.no_remainder:
    push    ecx     ; 暂存页表个数



;  为简化处理  所有线性地址对应相等的物理地址
;首先初始化页目录
    mov ax, SelectorPageDir;此段首地址为pagedirbase
    mov es, ax
    mov ecx, 1024 ; 共1K个表项
    xor edi, edi
    xor eax, eax
    mov eax, PageTblBase|PG_P|PG_USU|PG_RWW
.1:
    stosd        ;取得双字mov [edi], eax,  edi = edi+4;
    add eax, 4096;  为了简化 所有页表在内存中都是连续的
    loop .1

    ;再初始化所有页表(1K个  4M内存空间)
    mov ax, SelectorPageTbl;  此段首地址为 pagetblbase
    mov es, ax

    pop eax ; 页表个数从堆栈里弹出来
    mov ebx, 1024
    mul ebx
    mov ecx, eax;  PTE个数 1024*页表个数

    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
    mov cr3, eax    ;cr3 指向页目录表
    mov eax, cr0
    or  eax, 80000000h
    mov cr0, eax   ;PG = 1  分页机制生效
    jmp short .3
.3:
    nop
    ret
    ;
;分页机制启动完毕


DispMemSize:
    push    esi
    push    edi
    push    ecx
    mov esi, MemChkBuf
    mov ecx, [dwMCRNumber];for(int i=0;i<[MCRNumber];i++)//每次得到一个ARDS
.loop:                ;{
    mov edx, 5        ;  for(int j=0;j<5;j++) //每次得到一个ARDS中的成员  每个四字节 共20字节
    mov edi, ARDStruct    ;  {//依次显示BaseAddrLow,BaseAddrHigh,LengthLow,
.1:               ;             LengthHigh,Type
    push    dword [esi]   ;
    call    DispInt       ;    DispInt(MemChkBuf[j*4]); //显示一个成员
    pop eax       ;
    stosd             ;    ARDStruct[j*4] = MemChkBuf[j*4];
    add esi, 4        ;
    dec edx       ;
    cmp edx, 0        ;
    jnz .1        ;  }
    call    DispReturn    ;  printf("\n");
    cmp dword [dwType], 1 ;  if(Type == AddressRangeMemory)
    jne .2        ;  {
    mov eax, [dwBaseAddrLow];
    add eax, [dwLengthLow];
    cmp eax, [dwMemSize]  ;    if(BaseAddrLow + LengthLow > MemSize)
    jb  .2        ;
    mov [dwMemSize], eax  ;    MemSize = BaseAddrLow + LengthLow;
.2:               ;  }
    loop    .loop         ;}
                  ;
    call    DispReturn    ;printf("\n");
    push    szRAMSize     ;
    call    DispStr       ;printf("RAM size:");
    add esp, 4        ;
                  ;
    push    dword [dwMemSize] ;
    call    DispInt       ;DispInt(MemSize);
    add esp, 4        ;

    pop ecx
    pop edi
    pop esi
    ret


%include "lib.inc"   




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
    and eax, 7ffffffeh
    mov cr0, eax

LABEL_GO_BACK_TO_REAL:
    jmp 0:LABEL_REAL_ENTRY;    段地址会在程序开始处被设置为正确的值

Code16Len equ $ - LABEL_SEG_CODE16

;end of section .s16code
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值