学习笔记
《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f
习题12-1:修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响)。
- 要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量。建议对每个双字单元用两个花码
0x55AA55AA
和0xAA55AA55
进行检测。 - 分析:指定一块连续的内存区域,以双字为单元,写入
0x55AA55AA
再读出并与0x55AA55AA
比较,看是否相等;如果相等则,再写入0xAA55AA55
再再读出并与0xAA55AA55
比较,看是否相等;两次都相等,说明通过检测;
代码功能
- 以双字为单元,利用两个花码反复写入读出来检测内存;
- 在屏幕上显示
已经通过检测的单元个数 / 需要检测的单元总数
(两个数值均以十六进制显示); - 每通过一次检测,屏幕上的字符 感叹号! 闪烁一次;
- 指定的内存区域全部检测通过后,在屏幕上显示字符串 "OK";
运行测试
习题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
完全一致
- 增加常量
;---------------------------------------------------------------
;定义常量
;---------------------------------------------------------------
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的这位博主还实现了一个很漂亮的进度条,提供的答案很棒!
- 代码整个结构(各个部分在内存中的映象)参考
- 子程序check的实现修改自书上第六章的显示各个数位
网友评论