pmtest8.asm

私は長い間バグを探していました、前のコードは

LABEL_DESC_CODE32:記述子0、SegCode32Len-1、DA_C | DA_32;

コードは今です

LABEL_DESC_CODE32:記述子0、SegCode32Len-1、DA_CR | DA_32;一貫性のないコードセグメント

このため、プログラムが出ません。DA_Cが実行可能な
コードセグメント属性の
存在であることを意図的に確認しました。DA_CRは実行可能で読み取り可能なコードセグメント属性です。

このプログラムの操作の1つは、最初に指定された場所でプログラムを読み書きし、次に指定された場所で実行することです。これはFOO BAR PagingDemoProcの3つのプログラムです。ただし、これら3つのプログラムはすべてCODE32に配置されているため、CODE32もDA_CR

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

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_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_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_CR| 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
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]



;这是一个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:

    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

    push    szMemChkTitle
    call    DispStr
    add esp, 4

    call    DispMemSize     ; 显示内存信息

;   call    SetupPaging     ; 启动分页机制
    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    ; 测试edx 是否为空 edx是放余数的位置
    jz  .no_remainder
    inc ecx     ; 如果余数不为 0 就需增加一个页表
.no_remainder:
    ;push   ecx     ; 暂存页表个数
    mov [PageTableNumber], ecx  ;暂存页表个数


;  为简化处理  所有线性地址对应相等的物理地址
;首先初始化页目录
    mov ax, SelectorFlatRW  ;此段首地址为pagedirbase
    mov es, ax
    ;xor    edi, edi
    mov edi, PageDirBase0  ;此段首地址是pagedirbase0
    xor eax, eax
    mov eax, PageTblBase0|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
;由于这次页目录和页表放在一个段里面  所以不用设置es    
    mov eax, [PageTableNumber];  页表个数
;   pop eax ; 页表个数从堆栈里弹出来
    mov ebx, 1024
    mul ebx
    mov ecx, eax;  PTE个数 1024*页表个数  多少个页

;   xor     edi, edi
    mov edi, 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    ;cr3 指向页目录表
    mov eax, cr0
    or  eax, 80000000h
    mov cr0, eax   ;PG = 1  分页机制生效
    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 ;  //00401000  二进制 0000 0000 0100 0000 0001 0000 0000 0000
    shr eax, 22                ;页目录表所在的项 0000 0000 01
    mov ebx, 4096
    mul ebx
    mov ecx, eax        ;LinearAddDemo 代码所在的页表  4096  0x1000h
    mov eax, LinearAddrDemo
    shr eax, 12
    and eax, 03FFh  ; 1111111111b (10 bits)  取中间的10位  00 0000 0001
    mov ebx, 4
    mul ebx     ;   0x04
    add eax, ecx        ;   0x1004  获得指向linarAddDemo所在的页 需要访问里面的内容 改变所指向的页
    add eax, PageTblBase1   ;212004h 再加上页表首地址 PageTblBase1=211000h
    mov dword [es:eax], ProcBar | PG_P | PG_USU | PG_RWW ;这句将对应该页表中对应的页的地址改了

;对于0x00211000页表首地址  多了1004h  
;0x00211000对应的是00000000h

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

    ret
; ---------------------------------------------------------------------------

PagingDemoProc:
OffsetPagingDemoProc    equ PagingDemoProc - $$
    mov eax, LinearAddrDemo
    call    eax
    retf
LenPagingDemoAll    equ $ - PagingDemoProc

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:
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
.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

おすすめ

転載: blog.csdn.net/u012323667/article/details/79429555