|
|
第14章习题
1.修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x00100000开始,不考虑高速缓存的影响)。要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量。建议对每个双字单元用两个花码0x55AA55AA和0xAA55AA55进行检测。
答案:
此题通过保护模式下的内存访问练习,综合考察巩固前面已经学过的知识,包括GDT,描述符,等等。
以下程序用了1个小时编写,并且已验证。2026-03-16,周一
- ;检测物理内存并显示进度
- ;最终定格的数字就是你的内存的总字节数。
- ;这是一个主引导扇区程序,要写入主引导扇区再运行!!
- ;设置堆栈段和栈指针
- mov eax,cs
- mov ss,eax
- mov sp,0x7c00
- ;计算GDT所在的逻辑段地址
- mov eax,[cs:pgdt+0x7c00+0x02] ;GDT的32位物理地址
- xor edx,edx
- mov ebx,16
- div ebx ;分解成16位逻辑地址
- mov ds,eax ;令DS指向该段以进行操作
- mov ebx,edx ;段内起始偏移地址
- ;创建0#描述符,它是空描述符,这是处理器的要求
- mov dword [ebx+0x00],0x00000000
- mov dword [ebx+0x04],0x00000000
- ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
- mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xfffff
- mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符
- ;创建保护模式下初始代码段描述符
- mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,512字节
- mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符
- ;创建以上代码段的别名描述符
- mov dword [ebx+0x18],0x7c0001ff ;基地址为0x00007c00,512字节
- mov dword [ebx+0x1c],0x00409200 ;粒度为1个字节,数据段描述符
- ;保护模式下的栈段描述符
- mov dword [ebx+0x20],0x7c00fffe ;基地址为0x00007c00,界限为0xffffe
- mov dword [ebx+0x24],0x00cf9600 ;粒度为4KB,向下扩展
- ;初始化描述符表寄存器GDTR
- mov word [cs: pgdt+0x7c00],39 ;描述符表的界限
- lgdt [cs: pgdt+0x7c00]
- in al,0x92 ;南桥芯片内的端口
- or al,0000_0010B
- out 0x92,al ;打开A20
- cli ;中断机制尚未工作
- mov eax,cr0
- or eax,1
- mov cr0,eax ;设置PE位
- ;以下进入保护模式... ...
- jmp 0x0010:dword flush ;16位的描述符选择子:32位偏移
- [bits 32]
- flush:
- ;0x08->4GB数据段选择子;0x10->初始代码段选择子;
- ;0x18->代码段别名段选择子;0x20->栈段选择子。
- mov eax,0x0008 ;加载数据段(0..4GB)选择子
- mov ds,eax
- mov es,eax
- mov fs,eax
- mov gs,eax
- mov eax,0x0020 ;0000 0000 0010 0000
- mov ss,eax
- xor esp,esp ;ESP <- 0
- mov eax,0x100000 ;初始的物理地址
- do_again:
- call show_addr ;显示这个地址
- ;以下测试这个地址。
- mov dword [eax],0x55aa55aa
- cmp dword [eax],0x55aa55aa
- jne do_exit
- mov dword [eax],0xaa55aa55
- cmp dword [eax],0xaa55aa55
- jne do_exit
- add eax,4
- jmp do_again
- ;最终定格的数字就是你的内存的总字节数。
- do_exit:
- jmp $
- ;-------------------------------------------------------------------------------
- ;显示地址 输入:EAX=地址的数值
- show_addr:
- push eax
- push ebx
- push ecx
- push edx
- ;以下分解和压栈每个数位
- mov ebx,10
- xor cx,cx ;cx用来保存压栈次数以便将来出栈
- @d:
- inc cx
- xor edx,edx
- div ebx
- or dl,0x30
- push dx
- cmp eax,0
- jne @d
- ;以下显示各个数位
- xor eax,eax
- @a:
- pop dx
- mov dh,0x07
- mov [eax+0xb8000],dx ;通过4GB段访问显存
- add eax,2
- loop @a
- pop edx
- pop ecx
- pop ebx
- pop eax
- ret
- ;-------------------------------------------------------------------------------
- pgdt dw 0
- dd 0x00007e00
- times 510-($-$$) db 0
- db 0x55,0xaa
复制代码
2.有一个向下扩展的段,描述符中的B位和G位都是“1”。请问,如果希望段的大小为8KB,那么,描述符中的界限值应当是多少?
答案:
由于B位是1,则段界限的上界是 0xFFFFFFFF。段大小8KB,则下界限是0xFFFFFFFF-0x2000=0xFFFFDFFF
设描述符中的界限值是x,则0xFFFFDFFF=x*0x1000+0xFFF
求得x=0xFFFFD
|
|