pmtest7.asm

; =============根据内存大小分配页目录===============
; pmtest7.asm
; 编译方法:nasm pmtest7.asm -o pmtest7.com
; ==========================================

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

PageDirBase  equ 200000h ; 页目录开始地址: 2M
PageTblBase  equ 201000h ; 页表开始地址:  2M + 4K

org 0100h
 jmp LABEL_BEGIN

 

;=========================GDT=============================
[SECTION .gdt]
; GDT
;                                         段基址,       段界限     , 属性
LABEL_GDT:  Descriptor        0,                 0, 0   ; 空描述符
LABEL_DESC_NORMAL: Descriptor        0,            0ffffh, DA_DRW  ; Normal 描述符
LABEL_DESC_PAGE_DIR: Descriptor   PageDirBase,              4095, DA_DRW  ; Page Directory
LABEL_DESC_PAGE_TBL: Descriptor   PageTblBase,      4096 * 8 - 1, DA_DRW  ; Page Tables
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  ; 显存首地址
; GDT 结束

GdtLen  equ $ - LABEL_GDT ; GDT长度
GdtPtr  dw GdtLen - 1 ; GDT界限
  dd 0  ; GDT基地址

; GDT 选择子
SelectorNormal  equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorPageDir  equ LABEL_DESC_PAGE_DIR - LABEL_GDT
SelectorPageTbl  equ LABEL_DESC_PAGE_TBL - 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]

 

;======================DATA============================
[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 * 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 512 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]

 


;===========================STACK================================
; 全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
 times 512 db 0

TopOfStack equ $ - LABEL_STACK - 1

; END of [SECTION .gs]

 


;===========================16CODE_16===========================
[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

;------------------
 ; 得到内存描述信息  利用中断15h
 mov ebx, 0    ;第一次调用时ebx的值需为0
 mov di, _MemChkBuf    ;这里要存放BIOS的返回值(一个含有内存信息的数据结构)
.loop:
 mov eax, 0E820h
 mov ecx, 20   ;填充es:di的字节数(一般可忽略)
 mov edx, 0534D4150h  ; "SMAP"表示
 int 15h

 jc LABEL_MEM_CHK_FAIL ;CF=0表示出错啦
 add di, 20  ;指向下一结构体
 inc dword [_dwMCRNumber] ;每次加1,结构体的计数器
 cmp ebx, 0  ;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]

 

;==============================32CODE_32================================
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]

LABEL_SEG_CODE32:
 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


 ; 下面显示一个字符串
 push szPMMessage
 call DispStr
 add esp, 4

 push szMemChkTitle
 call DispStr
 add esp, 4
;-----------
 call DispMemSize  ; 显示内存信息

 call SetupPaging  ; 启动分页机制
;-----------
 ; 到此停止
 jmp SelectorCode16:0

; ---------------------------------------启动分页机制 ------------------------------------------
SetupPaging:
 ; 根据内存大小计算应初始化多少PDE以及多少页表
 xor edx, edx
 mov eax, [dwMemSize]
 mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
 div ebx
 mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
 test edx, edx
 jz .no_remainder
 inc ecx  ; 如果余数不为 0 就需增加一个页表
.no_remainder:
 push ecx  ; 暂存页表个数

 ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.

 ; 首先初始化页目录
 mov ax, SelectorPageDir ; 此段首地址为 PageDirBase
 mov es, ax
 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 ; 此段首地址为 PageTblBase
 mov es, ax
 pop eax   ; 页表个数
 mov ebx, 1024  ; 每个页表 1024 个 PTE
 mul ebx
 mov ecx, eax  ; PTE个数 = 页表个数 * 1024
 xor edi, edi
 xor eax, eax
 mov eax, PG_P  | PG_USU | PG_RWW
.2:
 stosd
 add eax, 4096  ; 每一页指向 4K 的空间
 loop .2

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

 ret
; 分页机制启动完毕 ----------------------------------------------------------

 

 

;--------------------------------显示内存大小------------------------------------
DispMemSize:
 push esi
 push edi
 push ecx

 mov esi, MemChkBuf
 mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++)
     ;// 每次得到一个ARDS(Address Range Descriptor Structure)结构
.loop:     ;{
 mov edx, 5   ; for(int j=0;j<5;j++) // 每次得到一个ARDS中的成员,共5个成员
 mov edi, ARDStruct  ; {  // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type
.1:     ;  DispInt(MemChkBuf[j*4]); // 显示一个成员
 push dword [esi]  ;
 call DispInt   ;  ARDStruct[j*4] = MemChkBuf[j*4];
 pop eax   ;
 stosd    ;
 add esi, 4   ;
 dec edx   ;
 cmp edx, 0   ;
 jnz .1   ; }
 call DispReturn  ; printf("/n");
 cmp dword [dwType], 1  ;if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2     ;
 jne .2   ; {
 mov eax, [dwBaseAddrLow] ;
 add eax, [dwLengthLow] ;
 cmp eax, [dwMemSize]  ;  if(BaseAddrLow + LengthLow > MemSize)
 jb .2   ;
 mov [dwMemSize], eax ;   MemSize = BaseAddrLow + LengthLow;
.2:     ; }
 loop .loop   ;}
     ;
 call DispReturn  ;printf("/n");
 push szRAMSize  ;
 call DispStr   ;printf("RAM size:");
 add esp, 4   ;
     ;
 push dword [dwMemSize] ;
 call DispInt   ;DispInt(MemSize);
 add esp, 4   ;

 pop ecx
 pop edi
 pop esi
 ret
;-------------------------------------------------------------------------------------------------

%include "lib.inc" ; 库函数

SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]

 

 

;===============================32CODE_16================================
; 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值