pmtest8

 

ContractedBlock.gifExpandedBlockStart.gifCode
; ==========================================
;
 pmtest8.asm
;
 编译方法:nasm pmtest8.asm -o pmtest8.com
;
 ==========================================

%INCLUDE    
"pm.inc"    ; 常量, 宏, 以及一些说明

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,                 00                ; 空描述符
LABEL_DESC_NORMAL:    Descriptor           0,            0ffffh, DA_DRW            ; Normal 描述符
LABEL_DESC_FLAT_C:    Descriptor             0,           0fffffh, DA_CR | DA_32 | DA_LIMIT_4K; 0 ~ 4G
LABEL_DESC_FLAT_RW:    Descriptor             0,           0fffffh, DA_DRW | DA_LIMIT_4K    ; 0 ~ 4G
LABEL_DESC_CODE32:    Descriptor           0,  SegCode32Len - 1, DA_CR | 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
SelectorFlatC        EQU    LABEL_DESC_FLAT_C    - LABEL_GDT
SelectorFlatRW        EQU    LABEL_DESC_FLAT_RW    - 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
_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

; 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    [_wSPValueInRealMode], SP

    
; 得到内存数
    MOV    EBX, 0
    
MOV    DI, _MemChkBuf
.
loop:
    
MOV    EAX, 0E820h
    
MOV    ECX, 20
    
MOV    EDX, 0534D4150h
    
INT    15h ;int15的调用后会把读取的内存信息(20字节),放到指定的位置,es:di地址开始的位置,当EBX为0的时候,表示没有进位了,内存读入完成
    JC    LABEL_MEM_CHK_FAIL
    
ADD    DI, 20
    
INC    dword [_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
    
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, [_wSPValueInRealMode]

    
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:
    
MOV    AX, SelectorData
    
MOV    DS, AX            ; 数据段选择子
    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 ;回复为ESP原来的值

    
PUSH    szMemChkTitle
    
CALL    DispStr
    
ADD    ESP, 4;回复为ESP原来的值


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


; 测试分页机制 --------------------------------------------------------------
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
; ---------------------------------------------------------------------------


; 切换页表 ------------------------------------------------------------------
PSwitch:
    
; 初始化页目录
    MOV    AX, SelectorFlatRW
    
MOV    ES, AX
    
MOV    EDI, PageDirBase1    ; 此段首地址为 PageDirBase1
    XOR    EAX, EAX
    
MOV    EAX, PageTblBase1 | PG_P  | PG_USU | PG_RWW
    
MOV    ECX, [PageTableNumber]
.
1:
    
stosd
    
ADD    EAX, 4096        ; 为了简化, 所有页表在内存中是连续的.
    LOOP    .1

    
; 再初始化所有页表
    MOV    EAX, [PageTableNumber]    ; 页表个数
    MOV    EBX, 1024        ; 每个页表 1024 个 PTE
    MUL    EBX
    
MOV    ECX, EAX        ; PTE个数 = 页表个数 * 1024
    MOV    EDI, PageTblBase1    ; 此段首地址为 PageTblBase1
    XOR    EAX, EAX
    
MOV    EAX, PG_P  | PG_USU | PG_RWW
.
2:
    
stosd
    
ADD    EAX, 4096        ; 每一页指向 4K 的空间
    LOOP    .2

    
; 在此假设内存是大于 8M 的
    MOV    EAX, LinearAddrDemo
    
SHR    EAX, 22
    
MOV    EBX, 4096
    
MUL    EBX
    
MOV    ECX, EAX
    
MOV    EAX, LinearAddrDemo
    
SHR    EAX, 12
    
AND    EAX, 03FFh    ; 1111111111b (10 bits)
    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
; ---------------------------------------------------------------------------


; PagingDemoProc ------------------------------------------------------------
PagingDemoProc:
OffsetPagingDemoProc    EQU    PagingDemoProc - $$
    
MOV    EAX, LinearAddrDemo
    
CALL    EAX
    
RETF
; ---------------------------------------------------------------------------
LenPagingDemoAll    EQU    $ - PagingDemoProc
; ---------------------------------------------------------------------------


; foo -----------------------------------------------------------------------
foo:
OffsetFoo    EQU    foo - $$
    
MOV    AH, 0Ch            ; 0000: 黑底    1100: 红字
    MOV    AL, 'F'
    
MOV    [gs:((80 * 17 + 0) * 2)], AX    ; 屏幕第 17 行, 第 0 列。
    MOV    AL, 'o'
    
MOV    [gs:((80 * 17 + 1) * 2)], AX    ; 屏幕第 17 行, 第 1 列。
    MOV    [gs:((80 * 17 + 2) * 2)], AX    ; 屏幕第 17 行, 第 2 列。
    RET
LenFoo    EQU    $ - foo
; ---------------------------------------------------------------------------


; bar -----------------------------------------------------------------------
bar:
OffsetBar    EQU    bar - $$
    
MOV    AH, 0Ch            ; 0000: 黑底    1100: 红字
    MOV    AL, 'B'
    
MOV    [gs:((80 * 18 + 0) * 2)], AX    ; 屏幕第 18 行, 第 0 列。
    MOV    AL, 'a'
    
MOV    [gs:((80 * 18 + 1) * 2)], AX    ; 屏幕第 18 行, 第 1 列。
    MOV    AL, 'r'
    
MOV    [gs:((80 * 18 + 2) * 2)], AX    ; 屏幕第 18 行, 第 2 列。
    RET
LenBar    EQU    $ - bar
; ---------------------------------------------------------------------------


; 显示内存信息 --------------------------------------------------------------
DispMemSize:
    
PUSH    ESI
    
PUSH    EDI
    
PUSH    ECX

    
MOV    ESI, MemChkBuf
    
MOV    ECX, [dwMCRNumber]    ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构
.loop:                    ;{
    MOV    EDX, 5            ;    for(int j=0;j<5;j++)    // 每次得到一个ARDS中的成员,共5个成员
    MOV    EDI, ARDStruct        ;    {            // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type
.1:                    ;
    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) // AddressRangeMemory : 1, AddressRangeReserved : 2
    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
    
MOV    cr0, EAX

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

Code16Len    EQU    $ - LABEL_SEG_CODE16

; END of [SECTION .s16code]

 

转载于:https://www.cnblogs.com/dfzx/archive/2009/06/05/1497033.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值