zoukankan      html  css  js  c++  java
  • pmtest8讲解

    稍微写了下注释

      1 ; ==========================================
      2 ; pmtest8.asm
      3 ; 编译方法:nasm pmtest8.asm -o pmtest8.com
      4 ; ==========================================
      5 
      6 %include    "pm.inc"    ; 常量, 宏, 以及一些说明
      7 
      8 PageDirBase0        equ    200000h    ; 页目录开始地址:    2M
      9 PageTblBase0        equ    201000h    ; 页表开始地址:        2M +  4K
     10 PageDirBase1        equ    210000h    ; 页目录开始地址:    2M + 64K
     11 PageTblBase1        equ    211000h    ; 页表开始地址:        2M + 64K + 4K
     12 
     13 LinearAddrDemo    equ    00401000h
     14 ProcFoo            equ    00401000h
     15 ProcBar            equ    00501000h
     16 
     17 ProcPagingDemo    equ    00301000h
     18 
     19 org    0100h
     20     jmp    LABEL_BEGIN
     21 
     22 [SECTION .gdt]
     23 ; GDT
     24 ;                                         段基址,       段界限     , 属性
     25 LABEL_GDT:        Descriptor           0,                 0, 0                ; 空描述符
     26 LABEL_DESC_NORMAL:    Descriptor           0,            0ffffh, DA_DRW            ; Normal 描述符
     27 LABEL_DESC_FLAT_C:    Descriptor             0,           0fffffh, DA_CR | DA_32 | DA_LIMIT_4K; 0 ~ 4G,可执行可读代码段
     28 LABEL_DESC_FLAT_RW:    Descriptor             0,           0fffffh, DA_DRW | DA_LIMIT_4K    ; 0 ~ 4G,可读写数据段
     29 LABEL_DESC_CODE32:    Descriptor           0,  SegCode32Len - 1, DA_CR | DA_32        ; 非一致代码段, 32
     30 LABEL_DESC_CODE16:    Descriptor           0,            0ffffh, DA_C            ; 非一致代码段, 16
     31 LABEL_DESC_DATA:    Descriptor           0,    DataLen - 1, DA_DRW            ; Data
     32 LABEL_DESC_STACK:    Descriptor           0,        TopOfStack, DA_DRWA | DA_32        ; Stack, 32 位
     33 LABEL_DESC_VIDEO:    Descriptor     0B8000h,            0ffffh, DA_DRW            ; 显存首地址
     34 ; GDT 结束
     35 
     36 GdtLen        equ    $ - LABEL_GDT    ; GDT长度
     37 GdtPtr        dw    GdtLen - 1    ; GDT界限
     38             dd    0        ; GDT基地址
     39 
     40 ; GDT 选择子
     41 SelectorNormal        equ    LABEL_DESC_NORMAL    - LABEL_GDT
     42 SelectorFlatC        equ    LABEL_DESC_FLAT_C    - LABEL_GDT
     43 SelectorFlatRW        equ    LABEL_DESC_FLAT_RW    - LABEL_GDT
     44 SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
     45 SelectorCode16        equ    LABEL_DESC_CODE16    - LABEL_GDT
     46 SelectorData        equ    LABEL_DESC_DATA        - LABEL_GDT
     47 SelectorStack        equ    LABEL_DESC_STACK    - LABEL_GDT
     48 SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
     49 ; END of [SECTION .gdt]
     50 
     51 [SECTION .data1]     ; 数据段
     52 ALIGN    32
     53 [BITS    32]
     54 LABEL_DATA:
     55 ; 实模式下使用这些符号
     56 ; 字符串
     57 _szPMMessage:            db    "In Protect Mode now. ^-^", 0Ah, 0Ah, 0    ; 进入保护模式后显示此字符串
     58 _szMemChkTitle:            db    "BaseAddrL BaseAddrH LengthLow LengthHigh   Type", 0Ah, 0    ; 进入保护模式后显示此字符串
     59 _szRAMSize            db    "RAM size:", 0
     60 _szReturn            db    0Ah, 0
     61 ; 变量
     62 _wSPValueInRealMode        dw    0
     63 _dwMCRNumber:            dd    0    ; Memory Check Result
     64 _dwDispPos:            dd    (80 * 6 + 0) * 2    ; 屏幕第 6 行, 第 0 列。
     65 _dwMemSize:            dd    0
     66 _ARDStruct:            ; Address Range Descriptor Structure
     67     _dwBaseAddrLow:        dd    0
     68     _dwBaseAddrHigh:    dd    0
     69     _dwLengthLow:        dd    0
     70     _dwLengthHigh:        dd    0
     71     _dwType:        dd    0
     72 _PageTableNumber        dd    0
     73 
     74 _MemChkBuf:    times    256    db    0
     75 
     76 ; 保护模式下使用这些符号
     77 szPMMessage        equ    _szPMMessage    - $$
     78 szMemChkTitle        equ    _szMemChkTitle    - $$
     79 szRAMSize        equ    _szRAMSize    - $$
     80 szReturn        equ    _szReturn    - $$
     81 dwDispPos        equ    _dwDispPos    - $$
     82 dwMemSize        equ    _dwMemSize    - $$
     83 dwMCRNumber        equ    _dwMCRNumber    - $$
     84 ARDStruct        equ    _ARDStruct    - $$
     85     dwBaseAddrLow    equ    _dwBaseAddrLow    - $$
     86     dwBaseAddrHigh    equ    _dwBaseAddrHigh    - $$
     87     dwLengthLow    equ    _dwLengthLow    - $$
     88     dwLengthHigh    equ    _dwLengthHigh    - $$
     89     dwType        equ    _dwType        - $$
     90 MemChkBuf        equ    _MemChkBuf    - $$
     91 PageTableNumber        equ    _PageTableNumber- $$
     92 
     93 DataLen            equ    $ - LABEL_DATA
     94 ; END of [SECTION .data1]
     95 
     96 
     97 ; 全局堆栈段
     98 [SECTION .gs]
     99 ALIGN    32
    100 [BITS    32]
    101 LABEL_STACK:
    102     times 512 db 0
    103 
    104 TopOfStack    equ    $ - LABEL_STACK - 1
    105 
    106 ; END of [SECTION .gs]
    107 
    108 
    109 [SECTION .s16]
    110 [BITS    16]
    111 LABEL_BEGIN:
    112     mov    ax, cs
    113     mov    ds, ax
    114     mov    es, ax
    115     mov    ss, ax
    116     mov    sp, 0100h
    117 
    118     mov    [LABEL_GO_BACK_TO_REAL+3], ax
    119     mov    [_wSPValueInRealMode], sp
    120 
    121     ; 得到内存数
    122     mov    ebx, 0
    123     mov    di, _MemChkBuf
    124 .loop:
    125     mov    eax, 0E820h
    126     mov    ecx, 20
    127     mov    edx, 0534D4150h
    128     int    15h
    129     jc    LABEL_MEM_CHK_FAIL
    130     add    di, 20
    131     inc    dword [_dwMCRNumber]
    132     cmp    ebx, 0
    133     jne    .loop
    134     jmp    LABEL_MEM_CHK_OK
    135 LABEL_MEM_CHK_FAIL:
    136     mov    dword [_dwMCRNumber], 0
    137 LABEL_MEM_CHK_OK:
    138 
    139     ; 初始化 16 位代码段描述符
    140     mov    ax, cs
    141     movzx    eax, ax
    142     shl    eax, 4
    143     add    eax, LABEL_SEG_CODE16
    144     mov    word [LABEL_DESC_CODE16 + 2], ax
    145     shr    eax, 16
    146     mov    byte [LABEL_DESC_CODE16 + 4], al
    147     mov    byte [LABEL_DESC_CODE16 + 7], ah
    148 
    149     ; 初始化 32 位代码段描述符
    150     xor    eax, eax
    151     mov    ax, cs
    152     shl    eax, 4
    153     add    eax, LABEL_SEG_CODE32
    154     mov    word [LABEL_DESC_CODE32 + 2], ax
    155     shr    eax, 16
    156     mov    byte [LABEL_DESC_CODE32 + 4], al
    157     mov    byte [LABEL_DESC_CODE32 + 7], ah
    158 
    159     ; 初始化数据段描述符
    160     xor    eax, eax
    161     mov    ax, ds
    162     shl    eax, 4
    163     add    eax, LABEL_DATA
    164     mov    word [LABEL_DESC_DATA + 2], ax
    165     shr    eax, 16
    166     mov    byte [LABEL_DESC_DATA + 4], al
    167     mov    byte [LABEL_DESC_DATA + 7], ah
    168 
    169     ; 初始化堆栈段描述符
    170     xor    eax, eax
    171     mov    ax, ds
    172     shl    eax, 4
    173     add    eax, LABEL_STACK
    174     mov    word [LABEL_DESC_STACK + 2], ax
    175     shr    eax, 16
    176     mov    byte [LABEL_DESC_STACK + 4], al
    177     mov    byte [LABEL_DESC_STACK + 7], ah
    178 
    179     ; 为加载 GDTR 作准备
    180     xor    eax, eax
    181     mov    ax, ds
    182     shl    eax, 4
    183     add    eax, LABEL_GDT        ; eax <- gdt 基地址
    184     mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址
    185 
    186     ; 加载 GDTR
    187     lgdt    [GdtPtr]
    188 
    189     ; 关中断
    190     cli
    191 
    192     ; 打开地址线A20
    193     in    al, 92h
    194     or    al, 00000010b
    195     out    92h, al
    196 
    197     ; 准备切换到保护模式
    198     mov    eax, cr0
    199     or    eax, 1
    200     mov    cr0, eax
    201 
    202     ; 真正进入保护模式
    203     jmp    dword SelectorCode32:0    ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处
    204 
    205 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    206 
    207 LABEL_REAL_ENTRY:        ; 从保护模式跳回到实模式就到了这里
    208     mov    ax, cs
    209     mov    ds, ax
    210     mov    es, ax
    211     mov    ss, ax
    212 
    213     mov    sp, [_wSPValueInRealMode]
    214 
    215     in    al, 92h        ;
    216     and    al, 11111101b    ; ┣ 关闭 A20 地址线
    217     out    92h, al        ;
    218 
    219     sti            ; 开中断
    220 
    221     mov    ax, 4c00h    ;
    222     int    21h        ; ┛回到 DOS
    223 ; END of [SECTION .s16]
    224 
    225 
    226 [SECTION .s32]; 32 位代码段. 由实模式跳入.
    227 [BITS    32]
    228 
    229 LABEL_SEG_CODE32:
    230     mov    ax, SelectorData
    231     mov    ds, ax            ; 数据段选择子
    232     mov    es, ax
    233     mov    ax, SelectorVideo
    234     mov    gs, ax            ; 视频段选择子
    235 
    236     mov    ax, SelectorStack
    237     mov    ss, ax            ; 堆栈段选择子
    238 
    239     mov    esp, TopOfStack
    240 
    241 
    242     ; 下面显示一个字符串
    243     push    szPMMessage
    244     call    DispStr
    245     add        esp, 4
    246 
    247     push    szMemChkTitle
    248     call    DispStr
    249     add        esp, 4
    250 
    251     call    DispMemSize        ; 显示内存信息
    252 
    253     call    PagingDemo        ; 演示改变页目录的效果
    254 
    255     ; 到此停止
    256     jmp    SelectorCode16:0
    257 
    258 ; 启动分页机制 --------------------------------------------------------------
    259 SetupPaging:
    260     ; 根据内存大小计算应初始化多少PDE以及多少页表
    261     xor    edx, edx
    262     mov    eax, [dwMemSize]
    263     mov    ebx, 400000h    ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
    264     div    ebx
    265     mov    ecx, eax    ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
    266     test    edx, edx
    267     jz    .no_remainder
    268     inc    ecx        ; 如果余数不为 0 就需增加一个页表
    269 .no_remainder:
    270     mov    [PageTableNumber], ecx    ; 暂存页表个数
    271 
    272     ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
    273 
    274     ; 首先初始化页目录
    275     mov    ax, SelectorFlatRW
    276     mov    es, ax
    277     mov    edi, PageDirBase0    ; 此段首地址为 PageDirBase0
    278     xor    eax, eax
    279     mov    eax, PageTblBase0 | PG_P  | PG_USU | PG_RWW
    280 .1:
    281     stosd
    282     add    eax, 4096        ; 为了简化, 所有页表在内存中是连续的,下一个页表的地址为下一个页目录项中的内容,eax中存放的是内容
    283     loop    .1
    284 
    285     ; 再初始化所有页表
    286     mov    eax, [PageTableNumber]    ; 页表个数
    287     mov    ebx, 1024        ; 每个页表 1024 个 PTE
    288     mul    ebx
    289     mov    ecx, eax        ; PTE个数 = 页表个数 * 1024
    290     mov    edi, PageTblBase0    ; 此段首地址为 PageTblBase0
    291     xor    eax, eax
    292     mov    eax, PG_P  | PG_USU | PG_RWW
    293 .2:
    294     stosd
    295     add    eax, 4096        ; 每一页指向 4K 的空间
    296     loop    .2
    297 
    298     mov    eax, PageDirBase0
    299     mov    cr3, eax   ;cr3页目录基地址寄存器
    300     mov    eax, cr0
    301     or    eax, 80000000h
    302     mov    cr0, eax
    303     jmp    short .3
    304 .3:
    305     nop
    306 
    307     ret
    308 ; 分页机制启动完毕 ----------------------------------------------------------
    309 
    310 
    311 ; 测试分页机制 --------------------------------------------------------------
    312 PagingDemo:
    313     mov    ax, cs
    314     mov    ds, ax
    315     mov    ax, SelectorFlatRW
    316     mov    es, ax
    317 
    318     push    LenFoo
    319     push    OffsetFoo
    320     push    ProcFoo
    321     call    MemCpy
    322     add        esp, 12
    323 
    324     push    LenBar
    325     push    OffsetBar
    326     push    ProcBar
    327     call    MemCpy
    328     add        esp, 12
    329 
    330     push    LenPagingDemoAll
    331     push    OffsetPagingDemoProc
    332     push    ProcPagingDemo
    333     call    MemCpy
    334     add        esp, 12
    335 
    336     mov    ax, SelectorData
    337     mov    ds, ax            ; 数据段选择子
    338     mov    es, ax
    339 
    340     call    SetupPaging        ; 启动分页
    341 
    342     call    SelectorFlatC:ProcPagingDemo
    343     call    PSwitch            ; 切换页目录,改变地址映射关系
    344     call    SelectorFlatC:ProcPagingDemo
    345 
    346     ret
    347 ; ---------------------------------------------------------------------------
    348 
    349 
    350 ; 切换页表 ------------------------------------------------------------------
    351 PSwitch:
    352     ; 初始化页目录
    353     mov    ax, SelectorFlatRW
    354     mov    es, ax
    355     mov    edi, PageDirBase1    ; 此段首地址为 PageDirBase1
    356     xor    eax, eax
    357     mov    eax, PageTblBase1 | PG_P  | PG_USU | PG_RWW
    358     mov    ecx, [PageTableNumber]
    359 .1:
    360     stosd
    361     add    eax, 4096        ; 为了简化, 所有页表在内存中是连续的.
    362     loop    .1
    363 
    364     ; 再初始化所有页表
    365     mov    eax, [PageTableNumber]    ; 页表个数
    366     mov    ebx, 1024        ; 每个页表 1024 个 PTE
    367     mul    ebx
    368     mov    ecx, eax        ; PTE个数 = 页表个数 * 1024
    369     mov    edi, PageTblBase1    ; 此段首地址为 PageTblBase1
    370     xor    eax, eax
    371     mov    eax, PG_P  | PG_USU | PG_RWW
    372 .2:
    373     stosd
    374     add    eax, 4096        ; 每一页指向 4K 的空间
    375     loop    .2
    376 
    377     ; 在此假设内存是大于 8M 的
    378     mov    eax, LinearAddrDemo
    379     shr    eax, 22
    380     mov    ebx, 4096
    381     mul    ebx
    382     mov    ecx, eax
    383     mov    eax, LinearAddrDemo
    384     shr    eax, 12
    385     and    eax, 03FFh    ; 1111111111b (10 bits)
    386     mov    ebx, 4
    387     mul    ebx
    388     add    eax, ecx
    389     add    eax, PageTblBase1
    390     mov    dword [es:eax], ProcBar | PG_P | PG_USU | PG_RWW
    391 
    392     mov    eax, PageDirBase1
    393     mov    cr3, eax
    394     jmp    short .3
    395 .3:
    396     nop
    397 
    398     ret
    399 ; ---------------------------------------------------------------------------
    400 
    401 
    402 ; PagingDemoProc ------------------------------------------------------------
    403 PagingDemoProc:
    404 OffsetPagingDemoProc    equ    PagingDemoProc - $$
    405     mov    eax, LinearAddrDemo
    406     call    eax
    407     retf
    408 ; ---------------------------------------------------------------------------
    409 LenPagingDemoAll    equ    $ - PagingDemoProc
    410 ; ---------------------------------------------------------------------------
    411 
    412 
    413 ; foo -----------------------------------------------------------------------
    414 foo:
    415 OffsetFoo    equ    foo - $$
    416     mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
    417     mov    al, 'F'
    418     mov    [gs:((80 * 17 + 0) * 2)], ax    ; 屏幕第 17 行, 第 0 列。
    419     mov    al, 'o'
    420     mov    [gs:((80 * 17 + 1) * 2)], ax    ; 屏幕第 17 行, 第 1 列。
    421     mov    [gs:((80 * 17 + 2) * 2)], ax    ; 屏幕第 17 行, 第 2 列。
    422     ret
    423 LenFoo    equ    $ - foo
    424 ; ---------------------------------------------------------------------------
    425 
    426 
    427 ; bar -----------------------------------------------------------------------
    428 bar:
    429 OffsetBar    equ    bar - $$
    430     mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
    431     mov    al, 'B'
    432     mov    [gs:((80 * 18 + 0) * 2)], ax    ; 屏幕第 18 行, 第 0 列。
    433     mov    al, 'a'
    434     mov    [gs:((80 * 18 + 1) * 2)], ax    ; 屏幕第 18 行, 第 1 列。
    435     mov    al, 'r'
    436     mov    [gs:((80 * 18 + 2) * 2)], ax    ; 屏幕第 18 行, 第 2 列。
    437     ret
    438 LenBar    equ    $ - bar
    439 ; ---------------------------------------------------------------------------
    440 
    441 
    442 ; 显示内存信息 --------------------------------------------------------------
    443 DispMemSize:
    444     push    esi
    445     push    edi
    446     push    ecx
    447 
    448     mov    esi, MemChkBuf
    449     mov    ecx, [dwMCRNumber]    ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构
    450 .loop:                    ;{
    451     mov    edx, 5            ;    for(int j=0;j<5;j++)    // 每次得到一个ARDS中的成员,共5个成员
    452     mov    edi, ARDStruct        ;    {            // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type
    453 .1:                    ;
    454     push    dword [esi]        ;
    455     call    DispInt            ;        DispInt(MemChkBuf[j*4]); // 显示一个成员
    456     pop    eax            ;
    457     stosd                ;        ARDStruct[j*4] = MemChkBuf[j*4];
    458     add    esi, 4            ;
    459     dec    edx            ;
    460     cmp    edx, 0            ;
    461     jnz    .1            ;    }
    462     call    DispReturn        ;    printf("\n");
    463     cmp    dword [dwType], 1    ;    if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2
    464     jne    .2            ;    {
    465     mov    eax, [dwBaseAddrLow]    ;
    466     add    eax, [dwLengthLow]    ;
    467     cmp    eax, [dwMemSize]    ;        if(BaseAddrLow + LengthLow > MemSize)
    468     jb    .2            ;
    469     mov    [dwMemSize], eax    ;            MemSize = BaseAddrLow + LengthLow;
    470 .2:                    ;    }
    471     loop    .loop            ;}
    472                     ;
    473     call    DispReturn        ;printf("\n");
    474     push    szRAMSize        ;
    475     call    DispStr            ;printf("RAM size:");
    476     add    esp, 4            ;
    477                     ;
    478     push    dword [dwMemSize]    ;
    479     call    DispInt            ;DispInt(MemSize);
    480     add    esp, 4            ;
    481 
    482     pop    ecx
    483     pop    edi
    484     pop    esi
    485     ret
    486 ; ---------------------------------------------------------------------------
    487 
    488 %include    "lib.inc"    ; 库函数
    489 
    490 SegCode32Len    equ    $ - LABEL_SEG_CODE32
    491 ; END of [SECTION .s32]
    492 
    493 
    494 ; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
    495 [SECTION .s16code]
    496 ALIGN    32
    497 [BITS    16]
    498 LABEL_SEG_CODE16:
    499     ; 跳回实模式:
    500     mov    ax, SelectorNormal
    501     mov    ds, ax
    502     mov    es, ax
    503     mov    fs, ax
    504     mov    gs, ax
    505     mov    ss, ax
    506 
    507     mov    eax, cr0
    508     and    al, 11111110b
    509     mov    cr0, eax
    510 
    511 LABEL_GO_BACK_TO_REAL:
    512     jmp    0:LABEL_REAL_ENTRY    ; 段地址会在程序开始处被设置成正确的值
    513 
    514 Code16Len    equ    $ - LABEL_SEG_CODE16
    515 
    516 ; END of [SECTION .s16code]

    关于分页,有一点要注意,如果按照4M-->4k来初始化,则寻址的时候按照10位-->10位-->12位来寻址

    过个春节,中间隔了好多天

  • 相关阅读:
    React项目(垃圾分类后台管理)
    React 学习笔记
    xml学习
    .NET Core部署Windows服务
    .NET 生成PDF流
    无线数传电台是什么
    电流电压采集模块如何进行数据传输的
    Spring5快乐教程(十)AspectJ注解实现AOP
    Spring5快乐教程(九)注解编程详解
    Spring5快乐教程(八)注解编程详解
  • 原文地址:https://www.cnblogs.com/cdwodm/p/2910081.html
Copyright © 2011-2022 走看看