DOS實方式下直接訪問4GB記憶體 |
|
jackkcg
站務副站長 發表:891 回覆:1050 積分:848 註冊:2002-03-23 發送簡訊給我 |
此為轉貼資料 http://depos.patching.net/showart.asp?art_id=80&cat_id=5 DOS實方式下直接訪問4GB記憶體 DOS實方式下直接訪問4GB記憶體
陳家祺
摘 要 本文分析了80486CPU的定址機制,提出了在實方式下直接訪
問4GB記憶體的策略和C程式設計方法。
關鍵字 DOS程式 擴展記憶體 程式設計
Scheme of the Direct Access 4GB Memory
in DOS Real Mode
Chen Jiaqi
ABSTRACT This paper makes an analysis of the principle about the access operation of 80486CPU, a approaches are posed for access 4GB memory and C Programming.
KEY WORDS DOS program; XMS; Programming;
0 引 言
在高檔PC微機系統中,如80486CPU微機系統,應用軟體的開發可以基於DOS系統的實方式,也可以基於Windows和OS/2系統的保護方式。如何在DOS系統的實方式下開發具有訪問擴展記憶體的應用程式,這是廣大軟體發展者關心的問題。其主要原因是:DOS系統是在PC機中應用最廣泛的作業系統,經過廣大用戶長年的應用和面向實際的軟體發展,其介面特性和編程方法被廣大軟體發展者所熟悉和掌握,並積累了豐富的應用程式資源、一系列功能強大的開發工具和一支巨大的DOS軟體發展隊伍。然而,開發基於DOS系統的實方式應用程式存在一定的局限性,主要是不能有效地利用高檔微機的記憶體資源,如擴展記憶體的訪問。尤其在開發即時性很強的大資料量的應用程式中,高效使用擴展記憶體是極?重要的。
目前常用的訪問擴展記憶體方法有:(1)採用“INT 15H”或HIMEM.SYS的功能調用。(2)採用虛擬磁片。前者只能實現資料塊在常規記憶體與擴展記憶體之間移動,這樣,不但還要佔用一定的常規記憶體空間,而且資料塊的移動還需佔用程式運行時間,使程式的運行效率降低。後者可以以文件的形式將資料存儲在擴展記憶體中,採用文件的訪問方式進行資料操作。顯然,這二種方法只能間接訪問擴展記憶體,不能直接訪問擴展記憶體。最大的缺點是資料的操作效率低,難以滿足即時性要求。
本文將從80486CPU(以下簡稱CPU)的定址機制研究入手,討論在實方式下直接訪問4GB記憶體的方法和C程式設計方法。
1 基本原理
1.1 物理位址形成的統一性
無論CPU在實方式下或保護方式下,其物理位址的形成都將使用段描述符高速緩衝寄存器。其差別是:
在實方式下,每當向段寄存器賦予新的內容(段地址)時,段描述符高速緩衝寄存器的基底位址值相應發生改變,其值?16×SEG,這就線性基底位址;CPU最終形成的物理位址?基底位址值加偏移量。段描述符高速緩衝寄存器的界限值和屬性值始終不變。當CPU重定後,CPU的工作模式?實方式,段描述符高速緩衝寄存器的界限值自動設置?FFFFH。因此,CPU能夠訪問記憶體的空間?0~10FFEFH(FFFFH×16+FFFFH),每個段的大小?64KB。
在保護方式下,每當向段寄存器賦予新的內容SEL(選擇字)時,段描述符高速緩衝寄存器的內容將由SEL對應的段描述符更新;段描述符高速緩衝寄存器的基底位址值、界限值和屬性值依據段描述符的設置而發生改變。段的基底位址可設置在4GB記憶體的任意位址處,段的最大界限值可達FFFFFFFFH(4GB-1)。在不分頁的情況下,CPU最終形成的物理位址同樣是基底位址值加偏移量。所以,CPU能夠整個訪問4GB記憶體空。
顯然,對於CPU在形成物理位址時,在實方式下與在0特權級不分頁的保護方式下是相同的。只是段的基底位址和段的大小設置範圍不同。工作方式確定是由控制寄存器CR0的最低位PE位決定的,若PE?0,則工作在實方式;若PE?1,則工作在保護方式。在通過PE位的改變時,就進行了工作方式切換。這種切換只影響段描述符高速緩衝寄存器的基底位址值運算方式,不影響段描述符高速緩衝寄存器的段界限值。
1.2 直接訪問4GB記憶體
當CPU重定後,CPU處於實方式下,儘管在實方式下可執行諸如“MOV AX,[ESI]”指令的32位元寄存器間接定址操作,但是ESI的內容必須在0~FFFFH範圍內,否則,將引起13號異常中斷。
基於CPU物理位址形成的統一性,在實方式下直接訪問4GB記憶體的關鍵是擴大段描述符高速緩衝寄存器的界限值。使諸如“MOV AX,[ESI]”指令的32位元寄存器間接定址操作實現4GB記憶體的訪問。然而,CPU在實方式下並沒有提供改變段描述符高速緩衝寄存器的界限值的操作指令。改變段描述符高速緩衝寄存器的內容只能在保護方式下進行,即向段寄存器賦予段的選擇字SEL,段描述符高速緩衝寄存器的內容將由SEL對應的段描述符更新。當CPU從保護方式切換到實方式時,段描述符高速緩衝寄存器的內容不發生變化。
因此,在DOS實方式下直接訪問4GB記憶體之前,讓CPU進入保護方式下,通過裝載具有4GB界限的段描述符到段描述符高速緩衝寄存器中去。然後返回到實方式下。CPU就可以通過32位寄存器間接定址操作實現4GB記憶體的訪問。
2 C程式設計
2.1 編程環境
本文採用Borland C++ 3.1程式設計環境,在程式中使用內嵌彙編方法實現特定的操作,在OPtions的“Compile”-“Advanced Code generation”中選擇386指令集。由於集成開發環境下的內部編譯器不能識別內嵌的386彙編指令,對於32位元寄存器和32位元位址操作彙編指令,可以採用直接在代碼前加入運算元字首0x66或位址字首0x67,以便實現32位寄存器或地址的操作。最好的方法是讓集成開發環境調用TASM.EXE進行編譯,即設置OPtions中的“Compile”-“Code generation”-“Compile via assemler”?ON。這樣便可完整地運用386彙編指令,在以下編程示例中採用這種編譯方法。
本程式是採用基於實方式下的編程方法。它不能在保護方式下和虛擬8086方式下運行,不能裝載延伸記憶體EMS驅動程式(如EMM386.EXE),因?,它使DOS系統處於虛擬8086方式下。
2.2 打開A20地址線
CPU的A20位址線受到鍵盤介面處理器8042的輸出口P21控制,如果DOS系統在?動後,沒有裝載XMS驅動程式(如himem.sys),此時A20被關閉,要訪問4GB記憶體,必須打開A20,使A20受到CPU的控制。
void openA20()
{ while(inp(0x64) & 2); outp(0x64,0xd1);
while(inp(0x64) & 2); outp(0x60,0xdf);
while(inp(0x64) & 2); outp(0x64,0xff);
}
2.3 設置資料段的4GB界限函數
首先,建立一個全局描述符表GDT,即GDT_def,它含有二個描述符,第一個?空描述符(保護方式下系統要求的),第二個是具有4GB段界限的資料段描述符。它的選擇字?8。再計算出GDT的基底位址和長度存入GDT_Addr中。然後,裝載GDT,進入保護方式,把選擇字8賦給DS和ES,此時第二個是具有4GB段界限的資料段描述符被裝載到DS和ES的描述符高速緩衝寄存器中。最後返回實方式。同理,也可設置FS和GS的4GB界限。
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基底位址和長度
void set4gb()
{ asm{
cli
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的長度存入GDT_Addr中
mov eax,ds //計算GDT描述符表的線性基底位址31-0
shl eax,4 //段地址eax=ds×16
xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
add eax,ebx //GDT的線性基底位址=eax+ebx
mov dword ptr GDT_Addr[2],eax //GDT的線性基底位址存入GDT_Addr中
lgdt fword ptr GDT_Addr
mov bx,8 //設置資料段描述符的選擇字
mov eax,cr0
or al,1
mov cr0,eax
jmp flush1
} //進入保護方式
flush1: asm{
mov ds,bx //DS裝載具有4GB界限的資料段描述符
mov es,bx //ES裝載具有4GB界限的資料段描述符
and al,0feh
mov cr0,eax
jmp flush2
} //返回實方式
flush2: asm{
pop es ; pop ds
sti
}
}
2.4 直接訪問4GB記憶體的基本函數
在DS和ES具有4GB的訪問界限後,通過32位元寄存器間接定址的指令就可實現4GB記憶體的訪問。以下僅給出位元組的讀寫函數,其中,addr?RAM的32位元線性位址。
(1)讀位元組函數 ,函數的返回值?讀出的位元組。
unsigned char read_ram(unsigned long addr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm mov esi,addr
asm mov al,[esi]
asm pop ds
return _AL;
}
(2)寫位元組函數,chr?要寫入的位元組。
void write_ram(unsigned long addr,unsigned char chr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm mov esi,addr
asm mov al,chr
asm mov [esi],al
asm pop ds
}
2.5 程式示例
本示例將使用上面所設計的功能函數,由內嵌組合語言程式完成對主機記憶體的測試和容量的檢測任務。在PC386/33、PC486/100上通過。
#include
------
********************************************************** 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |