24h購物| | PChome| 登入
2010-11-17 15:49:19| 人氣961| 回應0 | 上一篇 | 下一篇

[電腦知識] DOS實方式下直接訪問4GB記憶體

推薦 0 收藏 0 轉貼0 訂閱站台

http://depos.patching.net/showart.asp?art_id=80&cat_id=5 [此為轉貼資料]

DOS實方式下直接訪問4GB記憶體   陳家祺


摘要:本文分析了80486CPU的定址機制,提出了在實方式下直接訪問4GB記憶體的策略和C程式設計方法。
關鍵字:DOS程式 擴展記憶體 程式設計

〔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 assemle" = 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
#include
void main()
{
    unsigned long addr;
    openA20();
    set4gb();
    asm push ds
    asm mov ax,0
    asm mov ds,ax
    asm mov esi,00100000h                                                    //從1Mb開始測試
    N1: asm mov eax,[esi]                                                       //暫存esi地址指定雙字單元的內容
    asm mov dword ptr [esi],0                                                 //向esi地址指定雙字單元寫零
    asm mov ebx,[esi]                                                             //讀出由esi地址指定的雙字單元的內容給ebx
    asm mov dword ptr [esi],0ffffffffh                                   //向esi地址指定雙字單元寫全1
    asm mov ecx,[esi]                                                            //讀出由esi地址指定的雙字單元的內容給ecx
    asm mov [esi],eax                                                            //恢復esi地址指定雙字單元的內容
    asm inc ecx                                                                      //若ecx的內容?全1,ecx增一後,ecx=0
    asm cmp ebx,ecx                                                             //比較兩次讀出的內容
    asm jne N2                                                                       //不相等,則退出迴圈檢測
    asm add esi,4                                                                   //esi地址增4
    asm jmp N1                                                                    //繼續迴圈檢測
    N2: asm mov addr,esi
    asm pop ds
    printf("RAM = %ld(Mb)", addr >> 20 );
}

[3] 與XMS驅動程式的相容方法
3.1 基本原理
如果沒有裝載XMS驅動程式Himem.sys,採用上述方法可無限制地使用整個擴展記憶體。若系統中的某些系統程式和其他應用程式需要使用
Himem.sys,通過它分配和訪問擴展記憶體。這樣,擴展記憶體的部分空間被佔據,用戶應用程式所使用的擴展記憶體空間將受到限制,
否則,發生衝突。因此,在這種情況下,用戶應用程式可通過Himem.sys的功能調用,?其分配未使用的擴展記憶體存儲塊EMB,並通過鎖定
EMB,得到EMB的32位元線性基址。便可採用上述方法對存儲塊進行直接訪問。

3.2 Himem.sys的介面
(1)取得安裝狀態
只有當Himem.sys已被載入,才能調用它的功能。當AX=4300H時,執行“INT 2FH”軟中斷指令後,若AL=80H,則已載入;若AL=00H,則未載入。

(2)取得入口地址
Himem.sys的各項功能調用是通過功能調用的入口地址進行的,當AX=4310H時,執行“INT 2FH”軟中斷指令後,ES=入口的段位址,BX=入口的偏移地址。

(3)功能調用
Himem.sys?用戶提供許多XMS的記憶體管理功能,與本文相關的功能和介面如表1所示。
表1 HIMEM.SYS的主要功能與介面
功 能
入 口
出 口

取得空EMB
(擴展存儲塊)資訊
AH=08H
CALL HIMEM.SYS的入口地址
AX=最大連續的空EMB容量(KB)
DX=總計空EMB容量(KB)
請求分配EMB
AH=09H
DX=存儲塊長度(KB)
CALL HIMEM.SYS 的入口地址
AX=0001H 成功 DX=已分配EMB的控制碼
AX=0000H 失敗 DX=NULL
釋放EMB
AH=0AH
DX=要釋放已分配EMB的控制碼
CALL HIMEM.SYS的入口地址
AX=0001H 成功
AX=0000H 失敗
鎖定EMB
AH=0CH
DX=要鎖定的EMB的控制碼
CALL HIMEM.SYS的入口地址
AX=0001H 成功
DX:BX?EMB的32位元線性基底位址
AX=0000H 失敗
解除鎖定的EMB
AH=0DH
DX=解除被鎖定的EMB的控制碼
CALL HIMEM.SYS的入口地址
AX=0001H 成功
AX=0000H 失敗

4 結束語
DOS實方式下直接訪問4GB記憶體具有一定的特殊性和重要的實際意義。本文提出的方法在圖像即時識別系統中得到了成功的應用。
該系統需同時採集四幅圖像,每幅圖像512×512的256色點陣,四幅圖像共需1MB記憶體空間,在對圖像進行處理時還需要二幅圖像的工作緩衝區。
顯然,在常規記憶體中難以進行存儲和處理。若採用虛擬磁片或XMS驅動程式Himem.sys,由於圖像的資料量大,運算時間長,影響了即時性要求。
通過採用本文提出的方法,運用C程式的內嵌彙編直接對擴展記憶體進行圖像的存儲和處理。發揮了電腦的最大運行效率,滿足了即時性要求。
因此,本文提出的方法不但能應用於圖像處理系統,而且也適用于其他應用領域。其特點是:編程簡單、實現容易。可充分發揮和利用電腦的記憶體資源。

參 考 文 獻
1 陳家祺. DOS實方式下的保護方式程式設計方法. 湖北汽車工業學院學報,1997(1)
2 陳家祺. DOS應用程式使用擴展記憶體的C程式設計方法. 湖北汽車工業學院學報,1997(1)
3 朱傳乃. 386/486微型電腦系統原理與維修. 北京:人民郵電出版社,1995
4 何希才等. 80486微型電腦的原理及應用. 北京:人民郵電出版社,1994
5 周明德等. 80x86/80x87的結構與組合語言程式設計. 北京:清華大學出版社,1993


台長: 一隻貓
人氣(961) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 不分類

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文