3.3.6克勤可检用内存

 在这一小节中,我开始不怎么了解DispMemSize的作用,后来本着要一定要吃透代码的信念。DispMemSize的作用一定要跟前面得到内存数的代码联系起来才可以体会里面用法。DispMemSize里面的子程序就不讨论了,因为跟理解OS没直接关系。前面得到内存数代码里面,比较容易忽视的是ES:DI,这个指向一个描述符的数据结构。这个结构体里面就是执行完得到内存数代码后,BIOS向里面填充系统映像信息。比如说:BaseAddrLow……。

     还有一个比较容易忽视的要点是:stosd的用法。虽然说是stosd的作用是完成位串的传送。但应该要注意的是在32位指针下源指针是DS:ESI,目的指针是ES:EDI

      在这小节的对于的代码 PMTEST7.ASM我老是显示不出RAM size的正确值,都是显示0。为什么呢?是值没有正确赋进去?我开始猜测,又反复读DispMemSize代码,发现里面有赋值语句(mov [dwMemSize],eax)。后面也有将值显示出去的语句。反复对照课本跟PMTEST7.ASM里面的对应代码。就是发现不了错误在那。vcp老是崩溃掉。后来,我就把一段一段的代码从PMTEST7.ASM里面复制到我的代码里面,一个个的测试。后来发现了错误在。

     mov ax, SelectorData
 mov ds, ax   ; 数据段选择子
 mov ax, SelectorData
 mov es, ax
 mov ax, SelectorVideo
 mov gs, ax   ; 视频段选择子

 mov ax, SelectorStack
 mov ss, ax   ; 堆栈段选择子

 mov esp, TopOfStack
  如果你是用原来的PMTEST2.ASM 这里es是没有赋值的。这就造成DispMemSize里面的 edi 没有正确只向 ARDStruct。从而使用stosd的时候,源不能传到目的里面。从而造成RAM size里面的值不能正确显示。

 

附代码:

 ; ==========================================
; pmtest2.asm
; 编译方法:nasm pmtest2.asm -o pmtest2.com
; ==========================================

%include "pm.inc" ; 常量, 宏, 以及一些说明

PageDirBase equ 200000h;
PageTblBase equ 201000h
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 ; Stack, 32 位
LABEL_DESC_VIDEO: Descriptor  0B8000h,            0ffffh, DA_DRW  ; 显存首地址


LABEL_DESC_PAGE_DIR: Descriptor PageDirBase, 4095, DA_DRW
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 4096 * 8 -1, DA_DRW | DA_LIMIT_4K
; 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


SelectorPageDir equ LABEL_DESC_PAGE_DIR - LABEL_GDT
SelectorPageTbl equ LABEL_DESC_PAGE_TBL - LABEL_GDT
; END of [SECTION .gdt]

[SECTION .data1]  ; 数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode dw 0
; 字符串
PMMessage:  db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串
OffsetPMMessage  equ PMMessage - $$
StrTest:  db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTest  equ StrTest - $$

; 实模式下使用这些符号
; 字符串
_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 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。
_dwMemSize:   dd 0
_ARDStruct:   ; 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 - $$
ARDStruct  equ _ARDStruct - $$
 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] ;改成_wSPValueInRealMode 原来是的是没有_w前缀的

 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   ; 数据段选择子
 ;想不到在选择子这里多了一个es赋值
 mov ax, SelectorData
 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
 call SetupPaging   ;如果加了启动分页,就会导致vpc崩溃,但pmtest7.asm就不会,为什么呢?

 

 


 ; 到此停止
 jmp SelectorCode16:0

SetupPaging:
;************************
 xor edx, edx
 mov eax, [dwMemSize]
 mov ebx, 400000h   ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小 有疑问,这个值具体如何得来
 div ebx
 mov ecx, eax
 test edx, edx
 jz  .no_remainder
 inc ecx
.no_remainder:
 push ecx
;********************
 mov ax, SelectorPageDir
 mov es, ax
; mov ecx, 1024
 xor edi, edi
 xor eax, eax
 mov eax, PageTblBase | PG_P | PG_USU | PG_RWW
.1:
 stosd
 add eax, 4096
 loop .1

 mov ax, SelectorPageTbl
 mov es, ax
;*******************************
 pop eax
 mov ebx, 1024
 mul ebx
 mov ecx, eax
;**********************
; mov ecx, 1024*1024
 xor edi, edi
 xor eax, eax
 mov eax, PG_P | PG_USU | PG_RWW
.2:
 stosd
 add eax, 4096
 loop .2

 mov eax, PageDirBase
 mov cr3, eax
 mov eax, cr0
 or  eax, 80000000h
 mov cr0, eax
 jmp short .3
.3:nop
 ret

;***********************************
;DispMemSize
;********************************
DispMemSize:
push esi
push edi
push ecx

 mov esi, MemChkBuf
 mov ecx, [dwMCRNumber]
.loop:
 mov edx, 5
 mov edi, ARDStruct
.1:
 push dword [esi]
 call DispInt

 pop eax
 stosd
 add esi, 4
 dec edx
 cmp edx, 0
 jnz .1
 call DispReturn
 cmp dword [dwType], 1 ;改test
 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

%include "lib.inc"
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 al, 11111110b
 mov cr0, eax

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

Code16Len equ $ - LABEL_SEG_CODE16

; END of [SECTION .s16code]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值