[023][x86汇编语言]习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响)

学习笔记

《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f

习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响)。

  • 要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量。建议对每个双字单元用两个花码0x55AA55AA0xAA55AA55进行检测。
  • 分析:指定一块连续的内存区域,以双字为单元,写入0x55AA55AA再读出并与0x55AA55AA比较,看是否相等;如果相等则,再写入0xAA55AA55再再读出并与0xAA55AA55比较,看是否相等;两次都相等,说明通过检测;

代码功能

  • 双字为单元,利用两个花码反复写入读出来检测内存;
  • 在屏幕上显示 已经通过检测的单元个数 / 需要检测的单元总数 (两个数值均以十六进制显示)
  • 每通过一次检测,屏幕上的字符 感叹号! 闪烁一次;
  • 指定的内存区域全部检测通过后,在屏幕上显示字符串 "OK"

运行测试

[023][x86汇编语言]习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响)_第1张图片
习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响)
习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响

完整源码

    ;代码清单12-1
    ;文件名:ex12-1.asm
    ;文件说明:硬盘主引导扇区代码
    ;创建日期:16:23 2018/5/30

;---------------------------------------------------------------    
;定义常量
;---------------------------------------------------------------    
    MEMORY_START equ 0x100000           ;要检测的内存起始地址
    MEMORY_END   equ 0x500000           ;要检测的内存结束地址
    MEMORY_SIZE  equ (MEMORY_END-MEMORY_START)/4    ;以双字位单元
;---------------------------------------------------------------    
    
    ;设置堆栈段和栈指针
    mov eax,cs
    mov ss,eax
    mov sp,0x7c00
    
    ;计算GDT所在的逻辑段地址
    mov eax,[cs:pdgt+0x7c00+0x02]   ;GDT的32位线性基地址
    xor edx,edx
    mov ebx,16
    div ebx                         ;分解成16位逻辑地址
    
    mov ds,eax          ;令DS指向该段以进行操作:EAX低16位有效 DS=0x7e00
    mov ebx,edx         ;段内起始偏移地址:EDX EBX低16位有效 ebx=0x0000
    
    ;创建0#描述符,它是空描述符,这是处理器的要求
    mov dword [ebx+0x00],0x00000000
    mov dword [ebx+0x04],0x00000000
    
    ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
    mov dword [ebx+0x08],0x0000ffff     ;段基地址0x00000000
    mov dword [ebx+0x0c],0x00cf9200
    
    ;创建2#描述符,这是一个只执行的代码段
    mov dword [ebx+0x10],0x7c0001ff     ;段基地址0x00007C00
    mov dword [ebx+0x14],0x00409800
    
    ;创建3#描述符,这是上面代码段的别名
    mov dword [ebx+0x18],0x7c0001ff     ;段基地址0x00007C00
    mov dword [ebx+0x1c],0x00409200
    
    ;创建4#描述符,这是栈段
    mov dword [ebx+0x20],0x7c00fffe     ;段基地址0x00007C00
    mov dword [ebx+0x24],0x00cf9600
    
    ;初始化描述符寄存器GDTR
    mov word [cs:pdgt+0x7c00],39        ;5*8-1=39
    lgdt [cs:pdgt+0x7c00]
    
    in al,0x92                          ;南桥芯片的端口
    or al,0000_0010B
    out 0x92,al                         ;打开A20
    
    cli
    
    mov eax,cr0
    or eax,1
    mov cr0,eax                         ;设置PE位
    
    ;以下进入保护模式... ...
    jmp dword 0x0010:flush
    
    [bits 32]
flush:
    mov eax,0x0018      ;索引号3#
    mov ds,eax      
    
    mov eax,0x0008      ;索引号1#
    mov es,eax
    mov fs,eax
    mov gs,eax
    
    mov eax,0x0020      ;索引号4#
    mov ss,eax
    xor esp,esp         ;ESP=0
    
    mov dword [es:0x0b8000],0x072e0750  ;'P.'
    mov dword [es:0x0b8004],0x072e074d  ;'M.'
    mov dword [es:0x0b8008],0x07200720  ;'  '
    mov dword [es:0x0b800c],0x076b076f  ;'ok'

    
;---------------------------------------------------------------    
;显示需要检测的总的单元个数
;---------------------------------------------------------------        
    mov byte [es:0x0b8140],'H'
    mov byte [es:0x0b8142],'E'
    mov byte [es:0x0b8144],'X'
    mov byte [es:0x0b8146],':'
    
    mov ebp,0x0b8140+10
    mov ecx,0
    call check
    
    mov byte [es:0x0b8140+30],'/'
    
    mov ebp,0x0b8140+34
    mov ecx,MEMORY_SIZE
    call check
;---------------------------------------------------------------        
;内存检测
;以双字为单元,使用花码0x55aa55aa和0xaa55aa55进行内存检测
;---------------------------------------------------------------        
        
        xor ecx,ecx                 ;检测的单元个数
        mov ebx,MEMORY_START        ;检测的起始地址
exam:   
        mov dword [es:ebx],0x55aa55aa
        cmp dword [es:ebx],0x55aa55aa
        jnz err
        
        mov dword [es:ebx],0xaa55aa55
        mov dword [es:ebx],0xaa55aa55
        jnz err

        add ebx,4
        inc ecx
        mov byte  [es:0x0b80a0+28],'!'
        not byte  [es:0x0b80a0+29]
        
        
        mov ebp,0x0b8140+10
        call check
        
        cmp ebx,MEMORY_END
        jnz exam
        
        mov dword [es:0x0b80b0+20],0x076b076f       ;'ok'
        
;---------------------------------------------------------------        
err:
        hlt                         ;进入停机状态

        
;---------------------------------------------------------------
;子程序:check
;参数:    
;       ecx = 要显示的数值
;       ebp = 数值在显存的起始位置
;功能:    计算并显示检测的内存个数(以双字位单位)
;---------------------------------------------------------------
check:          push ebx
                push ecx
                push esi
                push eax
                push ebp
                
                mov eax,ecx
                xor ebx,ebx
                mov ecx,8
                mov esi,16
        digit:  
                xor edx,edx
                div esi
                mov [mem+ebx],dl
                inc ebx
                loop digit
                
                
                xor edi,edi
                xor ebx,ebx
                mov esi,7
        show:   
                mov al,[mem+esi]
                mov bl,al
                mov al,[number+ebx]
                mov [es:ebp+edi],al
                add edi,2
                dec esi
                jns show
        
                pop ebp
                pop eax
                pop esi
                pop ecx
                pop ebx
        
ret
;---------------------------------------------------------------
    mem     db  0,0,0,0,0,0,0,0     ;存放数位
    number  db '0123456789ABCDEF'
;---------------------------------------------------------------
    pdgt    dw  0
            dd  0x00007e00          ;GDT的物理地址
;---------------------------------------------------------------
    times 510-($-$$) db 0
                     db 0x55,0xaa

代码说明

  • 加载描述符部分以及进入保护模式与配书代码c12_mbr.asm 完全一致

https://www.jianshu.com/p/7447a004fe7f

  • 增加常量
;---------------------------------------------------------------    
;定义常量
;---------------------------------------------------------------    
    MEMORY_START equ 0x100000           ;要检测的内存起始地址
    MEMORY_END   equ 0x500000           ;要检测的内存结束地址
    MEMORY_SIZE  equ (MEMORY_END-MEMORY_START)/4    ;以双字位单元
;---------------------------------------------------------------    

  • 增加数据表,mem表存放数位,从number表中取出每个数位对应的ASCII码
    mem     db  0,0,0,0,0,0,0,0     ;存放数位
    number  db '0123456789ABCDEF'

解题参考

  • CSDN的这位博主还实现了一个很漂亮的进度条,提供的答案很棒!

https://blog.csdn.net/longintchar/article/details/50878960

  • 代码整个结构(各个部分在内存中的映象)参考

https://www.jianshu.com/p/7447a004fe7f

  • 子程序check的实现修改自书上第六章的显示各个数位

https://www.jianshu.com/p/f71416ec68ac

你可能感兴趣的:([023][x86汇编语言]习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响))