卓一笔记---显示系统总的内存大小

      忙碌了一阵,总算把分页管理的代码调通了.本节讲述系统内存的查询和显示,为分页管理实践做准备.分页管理前求出系统的总内存大小后,就可以根据实际的总内存大小初始化页目录表和页表,以便节省页目录表和页表占用的空间.

 1.首先构建文件pm.inc,初始化了一些需要的属性

DA_LDT EQU 82h;局部描述符表段类型值
DA_32  EQU 4000h ;32位段
DA_DRW		EQU	92h	; 存在的可读写数据段属性值
DA_DRWA		EQU	93h	; 存在的已访问可读写数据段类型值
DA_C  EQU  98h  ;存在的只执行代码段属性

DA_DPL1		EQU	  20h	; DPL = 1
DA_DPL3		EQU	  30h	; DPL = 3

SA_RPL0         EQU       0h    ;RPL = 0
SA_RPL1         EQU       1h    ;RPL = 1
SA_RPL2         EQU       2h    ;RPL = 2
SA_RPL3         EQU       3h    ;RPL = 3

SA_TIG		EQU	0	; ┓TI
SA_TIL		EQU	4	; ┛

;描述符定义,传进来的参数会自动装到对应的字节中
;usage:Descriptor Base,Limit,Attr
%macro Descriptor 3
       dw %2&0FFFFh ;段界限1
       dw %1&0FFFFh ;段基址1
       db (%1>>16)&0FFh ;段基址2
       dw ((%2>>8)&0F00h)|(%3&0F0FFh) ;属性1 + 段界限2 + 属性2
       db (%1>>24)&0FFh ;段基址3
%endmacro ;共8个字节

2.构建lib.inc文件,定义一些函数用来显示字符串和数字,为显示内存信息做准备.

;;lib.inc
;;显示AL中的数字
DispAL:
  push ecx
  push edx
  push edi
  
  mov edi,[dwDispPos]

  mov ah, 0Fh ;0 黑底, F白字
  mov dl, al
  shr al,4 ;先显示高位,再显示低位
  mov ecx,2
.begin:
  and al,01111b
  cmp al, 9
  ja .1
  add al,'0'
  jmp .2
.1:
  sub al,0Ah
  add al,'A'
.2:
  mov [gs:edi],ax
  add edi,2

  mov al,dl
  loop .begin
  ;add edi, 2

  mov [dwDispPos],edi

  pop edi
  pop edx
  pop ecx

  ret
;; DispAL 结束

;;显示一个整数
DispInt:
  mov eax, [esp + 4]
  shr eax,24
  call DispAL
  
  mov eax, [esp + 4]
  shr eax,16
  call DispAL

  mov eax, [esp + 4]
  shr eax,8
  call DispAL

  mov eax, [esp + 4]
  call DispAL

  mov ah,07h
  mov al,'h'
  
  push edi
  mov edi, [dwDispPos]
  mov [gs:edi], ax
  add edi,4
  mov [dwDispPos],edi
  pop edi

  ret
;;DispInt结束

;;显示一个字符串
DispStr:
  push ebp
  mov ebp,esp
  push ebx
  push esi
  push edi

  mov esi,[ebp+8] ;加上自己开始压入的ebp,一共压入了两个元素,因此加上8才能找到地址存放位置
  mov edi,[dwDispPos]
  mov ah,0Fh

.1:
  lodsb
  test al, al
  jz .2
  cmp al,0Ah ;是回车吗
  jnz .3
  push eax
  mov eax,edi
  mov bl,160
  div bl
  and eax,0FFh
  inc eax
  mov bl,160
  mul bl
  mov edi,eax
  pop eax
  jmp .1
.3:
  mov [gs:edi],ax
  add edi,2
  jmp .1
.2:
  mov [dwDispPos],edi

  pop edi
  pop esi
  pop ebx
  pop ebp
  ret
;;DispStr结束

;;换行
DispReturn:
  push szReturn
  call DispStr  ;printf("\n")
  add esp,4
  ret
;;DispReturn 结束

3.构建pmshowMem.asm文件,用int 15h中断求得系统内存的大小,并显示出来

%include "pm.inc" ;常量,宏,以及一些说明
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_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 ;32位Stack
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
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*14 + 0)*2
_dwMemSize dd 0
_ADRStruct:    ;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 - $$
ADRStruct equ _ADRStruct - $$
   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 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 ;显示内存信息

  jmp SelectorCode16:0 ;到此停止
  
  %include "lib.inc"  ;引入lib库中的函数
DispMemSize:
  push esi
  push edi
  push ecx
  
  mov esi,MemChkBuf
  mov ecx,[dwMCRNumber];每次得到一个ARDS,遍历内存结构数组

.loop:
   mov edx,5 ;每次得到ARDS中的一个成员
   mov edi,ADRStruct ;依次显示内存结构体中的成员

.1:
   push dword [esi]
   call DispInt  ;显示一个成员
   pop eax
   stosd  ;ADRStruct[j*4]=MemChkBuf[j*4]
   add esi,4
   dec edx
   cmp edx,0
   jnz  .1
   call DispReturn
   
   cmp dword [dwType],1; 看下内存是否可用
   jne .2
   mov eax,[dwBaseAddrLow]
   add eax,[dwLengthLow]
   cmp eax,[dwMemSize];
   jb  .2
   mov [dwMemSize],eax
.2:
   loop .loop
   call DispReturn
   push szRAMSize    ;显示内存大小标题
   call DispStr
   add esp,4
   push dword [dwMemSize]
   call DispInt 
   add esp,4
   pop ecx
   pop edi
   pop esi
   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     eax, 11111110b          ;关闭保护模式
	mov	cr0, eax

LABEL_GO_BACK_TO_REAL:
	jmp	0:LABEL_REAL_ENTRY	; 段地址会在程序开始处被设置成正确的值

Code16Len	equ	$ - LABEL_SEG_CODE16

; END of [SECTION .s16code]

4.构建MakeFileLDT文件

##################################################
# Makefile of pmtestx.asm (x=[1,2,3...])
##################################################

SRC:=pmshowMem.asm
BIN:=$(subst .asm,.com,$(SRC)) #${SRC}中的.asm会替换成.com
#此句等价于pmprotect2real.com

.PHONY : everything

everything : $(BIN)
	sudo mount -o loop pm.img /mnt/floppy/
	sudo cp $(BIN) /mnt/floppy/ -fv
	sudo umount /mnt/floppy/

$(BIN) : $(SRC)
	nasm $< -o $@ 

5.执行make -f MakeFileLDT编译程序,然后调用命令bochs -f bochsrcdos执行程序得到下面的结果

源码地址:https://github.com/Foolegend/aos/tree/master/chapter03/Page/showMem

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值