zoukankan      html  css  js  c++  java
  • 31 获取物理内存容量 上

    参考

    https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程

    我们知分页机制的关键是页请求和页置换,并且页置换发生在没有空闲页框的时候,但是现在出现了问题-是否可以知道还剩多少空闲页框?并且还有多少页框可用?--在这里就得获取物理内存的大小了

    一.获取物理内存容量

    在获取物理内存大小时,BIOS提供了一些操作方法

    A.相关中断(int 0x15)

    该中断的基础功能是(eax=0xE801)分别检测低15M和高16M-4G的内存,并且支持4GB内存检测,并且高级功能(eax=0xE820)可以遍历主机上所有的内存范围,获取各个内存范围的详细信息
    详细介绍下int 0x15的基础功能-中断参数为eax=0xE801,有三个重要的返回值,cf->成功置0,出错置1;ax,cx是以1kb为单位,表示15MB以下的内存容量;bx,dx是以64KB为单位,表示16MB以上的内存容量

    B.标志寄存器

    操作系统-获取物理内存容量
    对int 0x15基础功能进行简单示例介绍
    操作系统-获取物理内存容量
    15M以下内存容量左移10位(eax1024),16M以上内存容量先左移6位再左移10位(ebx64*1024)

    代码实验

    %include "inc.asm"
    
    org 0x9000
    
    jmp ENTRY_SEGMENT
    
    [section .gdt]
    ; GDT definition
    ;                                     段基址,           段界限,       段属性
    GDT_ENTRY       :     Descriptor        0,                0,           0
    CODE32_DESC     :     Descriptor        0,        Code32SegLen - 1,    DA_C + DA_32
    VIDEO_DESC      :     Descriptor     0xB8000,         0x07FFF,         DA_DRWA + DA_32
    DATA32_DESC     :     Descriptor        0,        Data32SegLen - 1,    DA_DRW + DA_32
    STACK32_DESC    :     Descriptor        0,         TopOfStack32,       DA_DRW + DA_32
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
    
    ; GDT Selector
    
    Code32Selector   equ (0x0001 << 3) + SA_TIG + SA_RPL0
    VideoSelector    equ (0x0002 << 3) + SA_TIG + SA_RPL0
    Data32Selector   equ (0x0003 << 3) + SA_TIG + SA_RPL0
    Stack32Selector  equ (0x0004 << 3) + SA_TIG + SA_RPL0
    ; end of [section .gdt]
    
    TopOfStack16    equ 0x7c00
    
    [section .dat]
    [bits 32]
    DATA32_SEGMENT:
        DTOS               db  "D.T.OS!", 0
        DTOS_OFFSET        equ DTOS - $$
        HELLO_WORLD        db  "Hello World!", 0
        HELLO_WORLD_OFFSET equ HELLO_WORLD - $$
    
    Data32SegLen equ $ - DATA32_SEGMENT
    
    ;
    MEM_SIZE   times 4   db  0
    
    [section .s16]
    [bits 16]
    ENTRY_SEGMENT:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, TopOfStack16
    
        ; get hardware memory infomation
        call GetMemSize
    
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
    
        call InitDescItem
    
        mov esi, DATA32_SEGMENT
        mov edi, DATA32_DESC
    
        call InitDescItem
    
        mov esi, STACK32_SEGMENT
        mov edi, STACK32_DESC
    
        call InitDescItem
    
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
    
        ; 1. load GDT
        lgdt [GdtPtr]
    
        ; 2. close interrupt
        cli 
    
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
    
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
    
        ; 5. jump to 32 bits code
        jmp dword Code32Selector : 0
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
    
        pop eax
    
        ret
    
    ;
    ;
    GetMemSize:
        push eax
        push ebx
        push ecx
        push edx
    
        mov dword [MEM_SIZE], 0
    
        xor eax, eax
        mov eax, 0xE801
    
        int 0x15
    
        jc geterr
    
        shl eax, 10   ; eax = eax * 1024;
    
        shl ebx, 6    ; ebx = ebx * 64;
        shl ebx, 10   ; ebx = ebx * 1024;
    
        add dword [MEaM_SIZE], eax
        add dword [MEM_SIZE], ebx
    
        jmp getok
    
    geterr:
        mov dword [MEM_SIZE], 0
    
    getok:
    
        pop edx
        pop ecx
        pop ebx
        pop eax
    
        ret
    
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:   
        mov ax, VideoSelector
        mov gs, ax
    
        mov ax, Stack32Selector
        mov ss, ax
    
        mov eax, TopOfStack32
        mov esp, eax
    
        mov ax, Data32Selector
        mov ds, ax
    
        mov ebp, DTOS_OFFSET
        mov bx, 0x0C
        mov dh, 12
        mov dl, 33
    
        call PrintString
    
        mov ebp, HELLO_WORLD_OFFSET
        mov bx, 0x0C
        mov dh, 13
        mov dl, 31
    
        call PrintString
    
        jmp $
    
    ; ds:ebp    --> string address
    ; bx        --> attribute
    ; dx        --> dh : row, dl : col
    PrintString:
        push ebp
        push eax
        push edi
        push cx
        push dx
    
    print:
        mov cl, [ds:ebp]
        cmp cl, 0
        je end
        mov eax, 80
        mul dh
        add al, dl
        shl eax, 1
        mov edi, eax
        mov ah, bl
        mov al, cl
        mov [gs:edi], ax
        inc ebp
        inc dl
        jmp print
    
    end:
        pop dx
        pop cx
        pop edi
        pop eax
        pop ebp
    
        ret
    
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    [section .gs]
    [bits 32]
    STACK32_SEGMENT:
        times 1024 * 4 db 0
    
    Stack32SegLen equ $ - STACK32_SEGMENT
    TopOfStack32  equ Stack32SegLen - 1
    

     

    操作系统-获取物理内存容量操作系统-获取物理内存容量操作系统-获取物理内存容量

    分析

    从上图首先对获取内存函数进行设置,并且对其进行调用,首先运行bochs得到打印结果,发现程序没有出现错误,但是在这里无法对内存进行查看,所以需要反编译,在该段函数中反编译中,由于是在16位进行的,所以不需要打印32反编译结果,在反编译之后,找到函数所对应的代码,并进行断点设置,如下所示
    操作系统-获取物理内存容量操作系统-获取物理内存容量操作系统-获取物理内存容量
    设置完之后,在bochs进行断点设置进行调试,同时需要找到内存改变的点对应的内存值,分别两次查看对应的内存情况,如下图所示
    操作系统-获取物理内存容量
    操作系统-获取物理内存容量
    操作系统-获取物理内存容量
    将得到的内存值通过进制转换为10进制可以得到
    操作系统-获取物理内存容量
    但是该结果不表示位MB,通过相除1024*1024得到的结果位31MB,但是在配置文件中得到的文件大小位32MB
    操作系统-获取物理内存容量操作系统-获取物理内存容量
    在这里获取的内存容量用两部分来表示,并且缺少1MB的原因是80286中的24根地址线最大寻址范围为16MB,之前在介绍两端的容量时,中间正好缺少1MB的内存
    操作系统-获取物理内存容量
    进行修改-添加1MB的内存
    操作系统-获取物理内存容量

    添加后代码如下:

    %include "inc.asm"
    
    org 0x9000
    
    jmp ENTRY_SEGMENT
    
    [section .gdt]
    ; GDT definition
    ;                                     段基址,           段界限,       段属性
    GDT_ENTRY       :     Descriptor        0,                0,           0
    CODE32_DESC     :     Descriptor        0,        Code32SegLen - 1,    DA_C + DA_32
    VIDEO_DESC      :     Descriptor     0xB8000,         0x07FFF,         DA_DRWA + DA_32
    DATA32_DESC     :     Descriptor        0,        Data32SegLen - 1,    DA_DRW + DA_32
    STACK32_DESC    :     Descriptor        0,         TopOfStack32,       DA_DRW + DA_32
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
              
              
    ; GDT Selector
    
    Code32Selector   equ (0x0001 << 3) + SA_TIG + SA_RPL0
    VideoSelector    equ (0x0002 << 3) + SA_TIG + SA_RPL0
    Data32Selector   equ (0x0003 << 3) + SA_TIG + SA_RPL0
    Stack32Selector  equ (0x0004 << 3) + SA_TIG + SA_RPL0
    ; end of [section .gdt]
    
    TopOfStack16    equ 0x7c00
    
    [section .dat]
    [bits 32]
    DATA32_SEGMENT:
        DTOS               db  "D.T.OS!", 0
        DTOS_OFFSET        equ DTOS - $$
        HELLO_WORLD        db  "Hello World!", 0
        HELLO_WORLD_OFFSET equ HELLO_WORLD - $$
    
    Data32SegLen equ $ - DATA32_SEGMENT
    
    ;
    MEM_SIZE   times 4   db  0
    
    [section .s16]
    [bits 16]
    ENTRY_SEGMENT:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, TopOfStack16
        
        ; get hardware memory infomation
        call GetMemSize
        
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
        
        call InitDescItem
        
        mov esi, DATA32_SEGMENT
        mov edi, DATA32_DESC
        
        call InitDescItem
        
        mov esi, STACK32_SEGMENT
        mov edi, STACK32_DESC
        
        call InitDescItem
        
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
    
        ; 1. load GDT
        lgdt [GdtPtr]
        
        ; 2. close interrupt
        cli 
        
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
        
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
        
        ; 5. jump to 32 bits code
        jmp dword Code32Selector : 0
    
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
        
        pop eax
        
        ret
    
    ;
    ;
    GetMemSize:
        push eax
        push ebx
        push ecx
        push edx
        
        mov dword [MEM_SIZE], 0
        
        xor eax, eax
        mov eax, 0xE801
        
        int 0x15
        
        jc geterr
        
        shl eax, 10   ; eax = eax * 1024;
        
        shl ebx, 6    ; ebx = ebx * 64;
        shl ebx, 10   ; ebx = ebx * 1024;
        
        mov ecx, 1
        shl ecx, 20   ; ecx = 1MB
        
        add dword [MEM_SIZE], eax
        add dword [MEM_SIZE], ebx
        add dword [MEM_SIZE], ecx
        
        jmp getok
        
    geterr:
        mov dword [MEM_SIZE], 0
        
    getok:
    
        pop edx
        pop ecx
        pop ebx
        pop eax
        
        ret
        
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:   
        mov ax, VideoSelector
        mov gs, ax
        
        mov ax, Stack32Selector
        mov ss, ax
        
        mov eax, TopOfStack32
        mov esp, eax
        
        mov ax, Data32Selector
        mov ds, ax
        
        mov ebp, DTOS_OFFSET
        mov bx, 0x0C
        mov dh, 12
        mov dl, 33
        
        call PrintString
        
        mov ebp, HELLO_WORLD_OFFSET
        mov bx, 0x0C
        mov dh, 13
        mov dl, 31
        
        call PrintString
        
        jmp $
    
    
    ; ds:ebp    --> string address
    ; bx        --> attribute
    ; dx        --> dh : row, dl : col
    PrintString:
        push ebp
        push eax
        push edi
        push cx
        push dx
        
    print:
        mov cl, [ds:ebp]
        cmp cl, 0
        je end
        mov eax, 80
        mul dh
        add al, dl
        shl eax, 1
        mov edi, eax
        mov ah, bl
        mov al, cl
        mov [gs:edi], ax
        inc ebp
        inc dl
        jmp print
    
    end:
        pop dx
        pop cx
        pop edi
        pop eax
        pop ebp
        
        ret
        
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    [section .gs]
    [bits 32]
    STACK32_SEGMENT:
        times 1024 * 4 db 0
        
    Stack32SegLen equ $ - STACK32_SEGMENT
    TopOfStack32  equ Stack32SegLen - 1
    

    通过之前相同的设置以及断点设置,得到的值为0x02000000,通过进制转换为33554432,通过计算为32MB.

      

  • 相关阅读:
    C#泛型
    QT QML Keys 处理注意事项
    Ubuntu 16.04 安装 QT Create 5.3.1
    在VMWare中安装了Ubuntu16.04,想要 Win10 中通过 SecureCRT 来操作
    Ubuntu16在VMWare中使用共享文件夹
    QT QLineEdit 获取焦点/获取焦点后全选字符
    QT Layout 布局的重要性
    QT ToolBar 工具栏浮动状态
    QT 格式化字符串功能
    QT 窗体之间(MainWindow 和 Dialog)数据传递
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14337945.html
Copyright © 2011-2022 走看看