操作系统分页机制

本文详细介绍了操作系统的分页存储机制,包括页的概念、逻辑地址与物理地址的转换、分页数据结构(页目录和页表)以及CR3寄存器的作用。通过实例展示了如何设置页目录和页表,最后启动分页机制,实现了虚拟存储器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一  页式存储

     1 概念

        所谓页就是一块内存,在80386中页的大小是4K,在奔腾中页的大小是2M或者4M 。

     2 逻辑地址 、 线性地址、物理地址

        在未打开分页机制前,线性地址等同于物理地址。可以认为,逻辑地址通过分段机制转换成线性地址。但当分页机制

开启时,逻辑地址先通过分段机制转换成线性地址,然后线性地址通过分页机制转换成物理地址。实现分页机制,主要是

实现虚拟存储器。

 

     3 分页数据结构

 

          转换采用两级页表,第一级叫做页目录,大小是4KB ,存储在一个物理页中,每个页表项大小是4KB 。每个页表项

对应第二级的一个页表,第二级的每一个页表也有1024个表项,每一个表项对用每一个物理页。页目录的表项简称为PDE

(page Directory entry) ,页表的表项简称为PTE(page Table Entry) 。

 

      进行转换时,先是从寄存器CR3指定的页目录中根据线性地址的高10位得到页表地址,然后在页表中根据线性地址的

12-21位,将这个首地址加上线性地址的低12位,就得到了物理地址。 10 位bit可以表示1024个选择,页目录中有1024改个目录项,则根据线性地址的高10位,就可以判断是哪个目录项,然后目录项中存储了页表的首地址。得到了页表的首地址

 

     分页机制是否有效的开关CR0的最高位PG位,如果分页有效那么PG位为1 。所以当我们设置好了 页目录表和页表,并

将CR3寄存器指向页目录表之后,只需要设置PG位,然后分页机制开始工作。

 

4 CR3 寄存器

   指向页目录的首地址,它的高20位是页目录表首地址的高20位,页目录表的低地址位会是0 ,也就是说页目录表是4KB

对齐的。

 

 

5 程序代码

; ==========================================
; pmtest6.asm
; 编译方法:nasm pmtest6.asm -o pmtest6.com
; ==========================================
 
%include    "pm.inc"    ; 常量, 宏, 以及一些说明
 
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,              1023, DA_DRW  | DA_LIMIT_4K        ; Page Tables, 4M
LABEL_DESC_CODE32:    Descriptor           0,  SegCode32Len - 1, DA_C + 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
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:
SPValueInRealMode    dw    0
; 字符串
PMMessage:        db    "In Protect Mode now. ^-^", 0    ; 进入保护模式后显示此字符串
OffsetPMMessage        equ    PMMessage - $$
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    [SPValueInRealMode], sp
 
    ; 初始化 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, [SPValueInRealMode]
 
    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:
    call    SetupPaging
 
    mov    ax, SelectorData
    mov    ds, ax            ; 数据段选择子
    mov    ax, SelectorVideo
    mov    gs, ax            ; 视频段选择子
 
    mov    ax, SelectorStack
    mov    ss, ax            ; 堆栈段选择子
 
    mov    esp, TopOfStack
 
 
    ; 下面显示一个字符串
    mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
    xor    esi, esi
    xor    edi, edi
    mov    esi, OffsetPMMessage    ; 源数据偏移
    mov    edi, (80 * 10 + 0) * 2    ; 目的数据偏移。屏幕第 10 行, 第 0 列。
    cld
.1:
    lodsb
    test    al, al
    jz    .2
    mov    [gs:edi], ax
    add    edi, 2
    jmp    .1
.2:    ; 显示完毕
 
    ; 到此停止
    jmp    SelectorCode16:0
 
; 启动分页机制 --------------------------------------------------------------
SetupPaging:
    ; 为简化处理, 所有线性地址对应相等的物理地址.
 
    ; 首先初始化页目录
    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
    add    eax, 4096        ; 为了简化, 所有页表在内存中是连续的.
    loop    .1
 
    ; 再初始化所有页表 (1K 个, 4M 内存空间)
    mov    ax, SelectorPageTbl    ; 此段首地址为 PageTblBase
    mov    es, ax
    mov    ecx, 1024 * 1024    ; 共 1M 个页表项, 也即有 1M 个页
    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
    mov    eax, cr0
    or    eax, 80000000h
    mov    cr0, eax
    jmp    short .3
.3:
    nop
 
    ret
; 分页机制启动完毕 ----------------------------------------------------------
 
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]

 

 

上述程序的页表使用了4MB的内存,这开销是相当大的,我们要克勤克俭用内存。在保护模式下,数据的地址应该是相对于

段地址的偏移。

 


6 克勤克俭用内存

 

  程序实现获取系统可用内存,利用int15 h 中断。

  地址范围描述符结构  ARDS

; ==========================================
; pmtest7.asm
; 编译方法:nasm pmtest7.asm -o pmtest7.com
; ==========================================
 
%include    "pm.inc"    ; 常量, 宏, 以及一些说明
 
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
LABEL_DESC_PAGE_TBL:    Descriptor   PageTblBase,      4096 * 8 - 1, DA_DRW        ; Page Tables
LABEL_DESC_CODE32:    Descriptor           0,  SegCode32Len - 1, DA_C + 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
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]
 
 
[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
    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    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
    jz    .no_remainder
    inc    ecx        ; 如果余数不为 0 就需增加一个页表
.no_remainder:
    push    ecx        ; 暂存页表个数
 
    ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
 
    ; 首先初始化页目录
    mov    ax, SelectorPageDir    ; 此段首地址为 PageDirBase
    mov    es, ax
    xor    edi, edi
    xor    eax, eax
    mov    eax, PageTblBase | PG_P  | PG_USU | PG_RWW
.1:
    stosd
    add    eax, 4096        ; 为了简化, 所有页表在内存中是连续的.
    loop    .1
 
    ; 再初始化所有页表
    mov    ax, SelectorPageTbl    ; 此段首地址为 PageTblBase
    mov    es, ax
    pop    eax            ; 页表个数
    mov    ebx, 1024        ; 每个页表 1024 个 PTE
    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
    mov    eax, cr0
    or    eax, 80000000h
    mov    cr0, eax
    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(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]

 

 

先执行某个线性地址处的模块,然后改变CR3来转换地址映射关系,再执行同一个线性地址处的模块,由于地址映射已经

改变,故应该得到两个不同的输出。

 

7 下面演示pmtest8.asm

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值