初步学习Protected Mode(6)

来源:互联网 发布:淘宝佣金查询 编辑:程序博客网 时间:2024/05/16 07:00

克勤克俭用内存。如果我们用了16MB的空间来存放页表,那么它映射了16G的内存空间,而我们的物理内存不一定有那么大(外星人之类的呵呵)。这实在是一种浪费,所以我们必须确定内存有多大,然后根据内存大小确定多少页表是可用的。

有很多方法,这里采用int15。

int 15输入:

eax 000E820h

ebx 放置着continuation value 第一次调用时ebx必须为0

es:di 指向ARDS BIOS将会填充此结构

ecx 用来设置BIOS填充ecx个字节,不过通常情况下BIOS会忽略ecx,总是填充20字节

edx 0534D4150h 'SWAP' BIOS会用到这个标志,对调用者将要请求的系统映像信息进行效验,这些信息会被BIOS放置到es:di所指向的结构中


int15 输出:

CF=0 表示没有错误,否则存在错误。

eax 0534D4150h

es:di 与输入值相同

ecx 同上

ebx 放置着等到下一个ARDS所需要的continuationvalue 这个值实际行驶依赖于BIOS,不必关心它的具体形势,只需要下次迭代时将其原封不动地放置到ebx中。若果ebx=0 那么并且CF没有进位表示它是最后一个地址范围描述符。


ARDS就是我们所说的地址范围描述符结构Address Range Descriptor Structure

ARDS偏移0位为BaseAddrLow,4位为BaseAddrHigh,8位为LengthLow,12位为LengthHigh,16Type位这个地址的地址类型。


Type取1,则表明这个内存段是一段可以被OS使用的RAM。若为2,表明不能被OS使用。

所以,我们在调用int 15h之前,必须先有一块缓冲区。我们在数据段中这样定义:

_MemChkBuf: times 256 db 0

我们可以再每得到一次内存描述时都使用同一缓冲区,然后对缓冲区里的数据进行处理,也可以将每次得到的数据放进不同的位置。我们采用后一种方式,定义了一块256B的缓冲区,它最多可以存放12个20B大小的结构体。这个大小仅仅是凭猜测而定,我们把每次得到内存信息连续写入这块缓冲区,在保护模式下将它们读出来显示在屏幕上,如下代码:


; ==========================================; pmtest7.asm; 编译方法:nasm pmtest7.asm -o pmtest7.com; ==========================================%include"pm.inc"; 常量, 宏, 以及一些说明PageDirBaseequ200000h; 页目录开始地址:2MPageTblBaseequ201000h; 页表开始地址:2M + 4Korg0100hjmpLABEL_BEGIN[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 DirectoryLABEL_DESC_PAGE_TBL:Descriptor   PageTblBase,      4096 * 8 - 1, DA_DRW; Page TablesLABEL_DESC_CODE32:Descriptor       0,  SegCode32Len - 1, DA_C + DA_32; 非一致代码段, 32LABEL_DESC_CODE16:Descriptor       0,            0ffffh, DA_C; 非一致代码段, 16LABEL_DESC_DATA:Descriptor       0,DataLen - 1, DA_DRW; DataLABEL_DESC_STACK:Descriptor       0,        TopOfStack, DA_DRWA + DA_32; Stack, 32 位LABEL_DESC_VIDEO:Descriptor 0B8000h,            0ffffh, DA_DRW; 显存首地址; GDT 结束GdtLenequ$ - LABEL_GDT; GDT长度GdtPtrdwGdtLen - 1; GDT界限dd0; GDT基地址; GDT 选择子SelectorNormalequLABEL_DESC_NORMAL- LABEL_GDTSelectorPageDirequLABEL_DESC_PAGE_DIR- LABEL_GDTSelectorPageTblequLABEL_DESC_PAGE_TBL- LABEL_GDTSelectorCode32equLABEL_DESC_CODE32- LABEL_GDTSelectorCode16equLABEL_DESC_CODE16- LABEL_GDTSelectorDataequLABEL_DESC_DATA- LABEL_GDTSelectorStackequLABEL_DESC_STACK- LABEL_GDTSelectorVideoequLABEL_DESC_VIDEO- LABEL_GDT; END of [SECTION .gdt][SECTION .data1] ; 数据段ALIGN32[BITS32]LABEL_DATA:; 实模式下使用这些符号; 字符串_szPMMessage:db"In Protect Mode now. ^-^", 0Ah, 0Ah, 0; 进入保护模式后显示此字符串_szMemChkTitle:db"BaseAddrL BaseAddrH LengthLow LengthHigh   Type", 0Ah, 0; 进入保护模式后显示此字符串_szRAMSizedb"RAM size:", 0_szReturndb0Ah, 0; 变量_wSPValueInRealModedw0_dwMCRNumber:dd0; Memory Check Result_dwDispPos:dd(80 * 6 + 0) * 2; 屏幕第 6 行, 第 0 列。_dwMemSize:dd0_ARDStruct:; Address Range Descriptor Structure_dwBaseAddrLow:dd0_dwBaseAddrHigh:dd0_dwLengthLow:dd0_dwLengthHigh:dd0_dwType:dd0_MemChkBuf:times256db0; 保护模式下使用这些符号szPMMessageequ_szPMMessage- $$szMemChkTitleequ_szMemChkTitle- $$szRAMSizeequ_szRAMSize- $$szReturnequ_szReturn- $$dwDispPosequ_dwDispPos- $$dwMemSizeequ_dwMemSize- $$dwMCRNumberequ_dwMCRNumber- $$ARDStructequ_ARDStruct- $$dwBaseAddrLowequ_dwBaseAddrLow- $$dwBaseAddrHighequ_dwBaseAddrHigh- $$dwLengthLowequ_dwLengthLow- $$dwLengthHighequ_dwLengthHigh- $$dwTypeequ_dwType- $$MemChkBufequ_MemChkBuf- $$DataLenequ$ - LABEL_DATA; END of [SECTION .data1]; 全局堆栈段[SECTION .gs]ALIGN32[BITS32]LABEL_STACK:times 512 db 0TopOfStackequ$ - LABEL_STACK - 1; END of [SECTION .gs][SECTION .s16][BITS16]LABEL_BEGIN:movax, csmovds, axmoves, axmovss, axmovsp, 0100hmov[LABEL_GO_BACK_TO_REAL+3], axmov[_wSPValueInRealMode], sp; 得到内存数movebx, 0movdi, _MemChkBuf.loop:moveax, 0E820hmovecx, 20movedx, 0534D4150hint15hjcLABEL_MEM_CHK_FAILadddi, 20incdword [_dwMCRNumber]cmpebx, 0jne.loopjmpLABEL_MEM_CHK_OKLABEL_MEM_CHK_FAIL:movdword [_dwMCRNumber], 0LABEL_MEM_CHK_OK:; 初始化 16 位代码段描述符movax, csmovzxeax, axshleax, 4addeax, LABEL_SEG_CODE16movword [LABEL_DESC_CODE16 + 2], axshreax, 16movbyte [LABEL_DESC_CODE16 + 4], almovbyte [LABEL_DESC_CODE16 + 7], ah; 初始化 32 位代码段描述符xoreax, eaxmovax, csshleax, 4addeax, LABEL_SEG_CODE32movword [LABEL_DESC_CODE32 + 2], axshreax, 16movbyte [LABEL_DESC_CODE32 + 4], almovbyte [LABEL_DESC_CODE32 + 7], ah; 初始化数据段描述符xoreax, eaxmovax, dsshleax, 4addeax, LABEL_DATAmovword [LABEL_DESC_DATA + 2], axshreax, 16movbyte [LABEL_DESC_DATA + 4], almovbyte [LABEL_DESC_DATA + 7], ah; 初始化堆栈段描述符xoreax, eaxmovax, dsshleax, 4addeax, LABEL_STACKmovword [LABEL_DESC_STACK + 2], axshreax, 16movbyte [LABEL_DESC_STACK + 4], almovbyte [LABEL_DESC_STACK + 7], ah; 为加载 GDTR 作准备xoreax, eaxmovax, dsshleax, 4addeax, LABEL_GDT; eax <- gdt 基地址movdword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址; 加载 GDTRlgdt[GdtPtr]; 关中断cli; 打开地址线A20inal, 92horal, 00000010bout92h, al; 准备切换到保护模式moveax, cr0oreax, 1movcr0, eax; 真正进入保护模式jmpdword SelectorCode32:0; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LABEL_REAL_ENTRY:; 从保护模式跳回到实模式就到了这里movax, csmovds, axmoves, axmovss, axmovsp, [_wSPValueInRealMode]inal, 92h; ┓andal, 11111101b; ┣ 关闭 A20 地址线out92h, al; ┛sti; 开中断movax, 4c00h; ┓int21h; ┛回到 DOS; END of [SECTION .s16][SECTION .s32]; 32 位代码段. 由实模式跳入.[BITS32]LABEL_SEG_CODE32:movax, SelectorDatamovds, ax; 数据段选择子movax, SelectorDatamoves, axmovax, SelectorVideomovgs, ax; 视频段选择子movax, SelectorStackmovss, ax; 堆栈段选择子movesp, TopOfStack; 下面显示一个字符串pushszPMMessagecallDispStraddesp, 4pushszMemChkTitlecallDispStraddesp, 4callDispMemSize; 显示内存信息callSetupPaging; 启动分页机制; 到此停止jmpSelectorCode16:0; 启动分页机制 --------------------------------------------------------------SetupPaging:; 根据内存大小计算应初始化多少PDE以及多少页表xoredx, edxmoveax, [dwMemSize]movebx, 400000h; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小divebxmovecx, eax; 此时 ecx 为页表的个数,也即 PDE 应该的个数testedx, edxjz.no_remainderincecx; 如果余数不为 0 就需增加一个页表.no_remainder:pushecx; 暂存页表个数; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.; 首先初始化页目录movax, SelectorPageDir; 此段首地址为 PageDirBasemoves, axxoredi, edixoreax, eaxmoveax, PageTblBase | PG_P  | PG_USU | PG_RWW.1:stosdaddeax, 4096; 为了简化, 所有页表在内存中是连续的.loop.1; 再初始化所有页表movax, SelectorPageTbl; 此段首地址为 PageTblBasemoves, axpopeax; 页表个数movebx, 1024; 每个页表 1024 个 PTEmulebxmovecx, eax; PTE个数 = 页表个数 * 1024xoredi, edixoreax, eaxmoveax, PG_P  | PG_USU | PG_RWW.2:stosdaddeax, 4096; 每一页指向 4K 的空间loop.2moveax, PageDirBasemovcr3, eaxmoveax, cr0oreax, 80000000hmovcr0, eaxjmpshort .3.3:nopret; 分页机制启动完毕 ----------------------------------------------------------DispMemSize:pushesipushedipushecxmovesi, MemChkBufmovecx, [dwMCRNumber];for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构.loop:;{movedx, 5;for(int j=0;j<5;j++)// 每次得到一个ARDS中的成员,共5个成员movedi, ARDStruct;{// 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type.1:;pushdword [esi];callDispInt;DispInt(MemChkBuf[j*4]); // 显示一个成员popeax;stosd;ARDStruct[j*4] = MemChkBuf[j*4];addesi, 4;decedx;cmpedx, 0;jnz.1;}callDispReturn;printf("\n");cmpdword [dwType], 1;if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2jne.2;{moveax, [dwBaseAddrLow];addeax, [dwLengthLow];cmpeax, [dwMemSize];if(BaseAddrLow + LengthLow > MemSize)jb.2;mov[dwMemSize], eax;MemSize = BaseAddrLow + LengthLow;.2:;}loop.loop;};callDispReturn;printf("\n");pushszRAMSize;callDispStr;printf("RAM size:");addesp, 4;;pushdword [dwMemSize];callDispInt;DispInt(MemSize);addesp, 4;popecxpopedipopesiret%include"lib.inc"; 库函数SegCode32Lenequ$ - LABEL_SEG_CODE32; END of [SECTION .s32]; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式[SECTION .s16code]ALIGN32[BITS16]LABEL_SEG_CODE16:; 跳回实模式:movax, SelectorNormalmovds, axmoves, axmovfs, axmovgs, axmovss, axmoveax, cr0andal, 11111110bmovcr0, eaxLABEL_GO_BACK_TO_REAL:jmp0:LABEL_REAL_ENTRY; 段地址会在程序开始处被设置成正确的值Code16Lenequ$ - LABEL_SEG_CODE16; END of [SECTION .s16code]

这里还需要一个inc文件

; ------------------------------------------------------------------------; 显示 AL 中的数字; ------------------------------------------------------------------------DispAL:pushecxpushedxpushedimovedi, [dwDispPos]movah, 0Fh; 0000b: 黑底    1111b: 白字movdl, alshral, 4movecx, 2.begin:andal, 01111bcmpal, 9ja.1addal, '0'jmp.2.1:subal, 0Ahaddal, 'A'.2:mov[gs:edi], axaddedi, 2moval, dlloop.begin;addedi, 2mov[dwDispPos], edipopedipopedxpopecxret; DispAL 结束-------------------------------------------------------------; ------------------------------------------------------------------------; 显示一个整形数; ------------------------------------------------------------------------DispInt:moveax, [esp + 4]shreax, 24callDispALmoveax, [esp + 4]shreax, 16callDispALmoveax, [esp + 4]shreax, 8callDispALmoveax, [esp + 4]callDispALmovah, 07h; 0000b: 黑底    0111b: 灰字moval, 'h'pushedimovedi, [dwDispPos]mov[gs:edi], axaddedi, 4mov[dwDispPos], edipopediret; DispInt 结束------------------------------------------------------------; ------------------------------------------------------------------------; 显示一个字符串; ------------------------------------------------------------------------DispStr:pushebpmovebp, esppushebxpushesipushedimovesi, [ebp + 8]; pszInfomovedi, [dwDispPos]movah, 0Fh.1:lodsbtestal, aljz.2cmpal, 0Ah; 是回车吗?jnz.3pusheaxmoveax, edimovbl, 160divblandeax, 0FFhinceaxmovbl, 160mulblmovedi, eaxpopeaxjmp.1.3:mov[gs:edi], axaddedi, 2jmp.1.2:mov[dwDispPos], edipopedipopesipopebxpopebpret; DispStr 结束------------------------------------------------------------; ------------------------------------------------------------------------; 换行; ------------------------------------------------------------------------DispReturn:pushszReturncallDispStr;printf("\n");addesp, 4ret; DispReturn 结束---------------------------------------------------------

这样一来,页表所占的空间就小得多,32MB的内存实际上只要32KB的页表就够了,所以在GDT中,这样初始化页表段:

LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 4096*8-1,DA_DRW

0 0
原创粉丝点击