DOS下如何访问4G内存
從表面上看,保護(hù)模式和實(shí)模式并沒(méi)有太大的區(qū)別,二者都使用了內(nèi)存段、中斷和設(shè)備驅(qū)動(dòng)來(lái)處理硬件,但二者有很多不同之處。我們知道,在實(shí)模式中內(nèi)存被劃分成段,每個(gè)段的大小為64KB,而這樣的段地址可以用16位來(lái)表示。內(nèi)存段的處理是通過(guò)和段寄存器相關(guān)聯(lián)的內(nèi)部機(jī)制來(lái)處理的,這些段寄存器(CS、DS、SS和ES)的內(nèi)容形成了物理地址的一部分。具體來(lái)說(shuō),最終的物理地址是由16位的段地址和16位的段內(nèi)偏移地址組成的。用公式表示為:
物理地址=左移4位的段地址+偏移地址。
在保護(hù)模式下,段是通過(guò)一系列被稱(chēng)之為“描述符表”的表所定義的。段寄存器存儲(chǔ)的是指向這些表的指針。用于定義內(nèi)存段的表有兩種:全局描述符表(GDT)和局部描述符表(LDT)。GDT是一個(gè)段描述符數(shù)組,其中包含所有應(yīng)用程序都可以使用的基本描述符。在實(shí)模式中,段長(zhǎng)是固定的(為64KB),而在保護(hù)模式中,段長(zhǎng)是可變的,其最大可達(dá)4GB。LDT也是段描述符的一個(gè)數(shù)組。與GDT不同,LDT是一個(gè)段,其中存放的是局部的、不需要全局共享的段描述符。每一個(gè)操作系統(tǒng)都必須定義一個(gè)GDT,而每一個(gè)正在運(yùn)行的任務(wù)都會(huì)有一個(gè)相應(yīng)的LDT。每一個(gè)描述符的長(zhǎng)度是8個(gè)字節(jié),格式如圖3所示。當(dāng)段寄存器被加載的時(shí)候,段基地址就會(huì)從相應(yīng)的表入口獲得。描述符的內(nèi)容會(huì)被存儲(chǔ)在一個(gè)程序員不可見(jiàn)的影像寄存器(shadow register)之中,以便下一次同一個(gè)段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實(shí)模式和保護(hù)模式的不同可以從圖1和圖2中很清楚地看出來(lái)。
此外,還有一個(gè)中斷描述符表(IDT)。這些中斷描述符會(huì)告訴處理器到那里可以找到中斷處理程序。和實(shí)模式一樣,每一個(gè)中斷都有一個(gè)入口,但是這些入口的格式卻完全不同。因?yàn)樵谇袚Q到保護(hù)模式的過(guò)程中沒(méi)有使用到IDT,所以在此就不多做介紹了。 2.GDT表 關(guān)于GDT表,你可以這樣理解:就是一串連續(xù)的變量.變量的大小是8字節(jié).而每一位均代表不同的意義,相關(guān)的說(shuō)明可以看一下其它的教程,都有詳細(xì)的解釋.其中第一個(gè)八字節(jié)變量必需保留,其值應(yīng)該為0.這里的每個(gè)變量(除了第一個(gè)保留變量)都定義了一個(gè)段,并描述出了這個(gè)段的起始位置,大小,屬性等.
接下去介紹如何進(jìn)入保護(hù)模式 可以分為以下幾個(gè)步驟: a.創(chuàng)建GDT表;
b.通過(guò)置PE位為1進(jìn)入保護(hù)模式;
c.執(zhí)行跳轉(zhuǎn)以清除在實(shí)模式下讀取的任何指令。 然后給出一個(gè)進(jìn)保護(hù)模式的具體例子:(匯編)
[BITS 16]
[ORG 0x8000]
jmp main
;∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑
;GDT定義.
;代碼段及數(shù)據(jù)段整合.占用整個(gè)內(nèi)存.
;∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑
GDT:
GdtNULL:
dw 0x0000
dw 0x0000
dw 0x0000
dw 0x0000
GdtCode:
dw 0xffff
dw 0x0000
dw 0x9a00 ;a為T(mén)ype表示,執(zhí)行,只讀
dw 0x00cf
GdtData:
dw 0xffff
dw 0x0000
dw 0x9200 ;2為T(mén)ype表示,讀/寫(xiě)
dw 0x00cf
GdtReg dw GdtReg-GDT-1
dd GDT
SelCode equ GdtCode-GDT
SelData equ GdtData-GDT
;-------------------GDT定義結(jié)束--------------------
main: ;內(nèi)核跳轉(zhuǎn)時(shí)將跳轉(zhuǎn)地址賦予bx
?? xor ax,ax
?? mov ds,ax
?? cli
?? lgdt [GdtReg]
?? sti
?? in al,92h ;打開(kāi)A20地址線.
?? or al,00000010b
?? out 92h,al
?? mov eax,cr0
?? or eax,1
?? mov cr0,eax
jmp DWord SelCode:Code32
[bits 32]
Code32:
?? mov ax,0x2c41
?? mov [0xb8000],ax
?? inc ax
?? mov [0xb8002],ax
jmp $
最后給出在dos下訪問(wèn)4G memory的具體c語(yǔ)言代碼如下:(BC3.1編譯通過(guò),386平臺(tái))
#include <dos.h>
///
//?? 4G Memory Access
// This Program Can Access 4G Bytes in DOS Real
//Mode,Needn't in Protection Mode It Works.
// The Program Enter 32 Bit Flat Mode a moment and
//Only Load FS a 32 Bit Flat Mode Selector,Then Return
//Real Mode.
// Used The FS Can Access All 4G Memory till It be
//reloaded.
//?? --By Southern. 1995.7.17
///
???
unsigned long GDT_Table[]=
{
?? 0,0,??? //NULL????? - 00H
?? 0x0000FFFF,0x00CF9A00, //Code32 - 08H Base=0 Limit=4G-1 Size=4G
?? 0x0000FFFF,0x00CF9200 //Data32 - 10H Base=0 Limit=4G-1 Size=4G
};
unsigned char OldIDT[6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp[6]={0}; //NULL The IDTR,IDTR's Limit=0 will
//disable all Interrupts,include NMI.
???
#define KeyWait() {while(inportb(0x64)&2);}
void A20Enable(void)
{
?? KeyWait();
?? outportb(0x64,0xD1);
?? KeyWait();
?? outportb(0x60,0xDF); //Enable A20 with 8042.
?? KeyWait();
?? outportb(0x64,0xFF);
?? KeyWait();
}
void LoadFSLimit4G(void)
{
?? A20Enable(); //Enable A20
?? //**************************************
?? //*????????????? Disable ints & Null IDT??????????? *
?? //**************************************
?? asm {
??? CLI??????????????????????? //Disable inerrupts
??? SIDT OldIDT //Save OLD IDTR
??? LIDT pdescr_tmp //Set up empty IDT.Disable any interrupts,
??? }?? //Include NMI.
?? //***************************************
?? //*??? Load GDTR *
?? //***************************************
?? asm { //The right Code is Real,But BC++'s Linker NOT Work with 32-bits Code.
??? db 0x66 //32 bit Operation Prefix in 16 Bit DOS.
??? MOV CX,DS??? //MOV ECX,DS
??? db 0x66??? //Get Data segment physical Address
??? SHL CX,4??? //SHL ECX,4
??? MOV word ptr pdescr_tmp[0],(3*8-1) //MOV word ptr pdescr_tmp[0],(3*8-1)
??? db 0x66
??? XOR AX,AX??? //XOR EAX,EAX
??? MOV AX,offset GDT_Table //MOV AX,offset GDT_Table
??? db 0x66
??? ADD AX,CX??? //ADD EAX,ECX
??? MOV word ptr pdescr_tmp[2],AX //GDTR Base high16 bits
??? db 0x66
??? SHR AX,16??? //SHR EAX,16
??? MOV word ptr pdescr_tmp[4],AX //GDTR Base high16 bits
??? LGDT pdescr_tmp?? //Load GDTR
??? }
?? //**************************************
?? //*??? Enter 32 bit Flat Protected Mode??? *
?? //**************************************
?? // Set CR0 Bit-0 to 1 Enter 32 Bit Protection
?? //Mode,And NOT Clear machine perform cache,It Meaning
?? //the after Code HAD Ready To RUN in 32 Bit Flat Mode,
?? //Then Load Flat Selector to FS and Description into it's
?? //Shadow register,After that,ShutDown Protection Mode
?? //And ReEnter Real Mode immediately.
?? // The FS holds Base=0 Size=4G Description and
?? //it can Work in Real Mode as same as Pretect Mode,
?? //untill FS be reloaded.
?? // In that time All the other Segment Registers are
?? //Not Changed,except FS.(They are ERROR Value holded in CPU).
?? asm {
??? MOV DX,0x10?? //The Data32 Selector
??? db 0x66,0x0F,0x20,0xC0 //MOV EAX,CR0
??? db 0x66
??? MOV BX,AX?? //MOV EBX,EAX
??? OR AX,1
??? db 0x66,0x0F,0x22,0xC0 //MOV CR0,EAX //Set Protection enable bit
??? JMP Flush
??? }??? //Clear machine perform cache.
?? Flush: //Now In Flat Mode,But The CS is Real Mode Value.
?? asm { //And it's attrib is 16-Bit Code Segment.
??? db 0x66
??? MOV AX,BX?? //MOV EAX,EBX
??? db 0x8E,0xE2 //MOV FS,DX //Load FS now
??? db 0x66,0x0F,0x22,0xC0 //MOV CR0,EAX //Return Real Mode.Now FS's Base=0 Size=4G
??? LIDT OldIDT?? //LIDT OldIDT?? //Restore IDTR
??? STI??? //STI //Enable INTR
??? }
}
//With FS can Access All 4G Memory Now.But if FS be reloaded in Real Mode
//It's Limit will Be Set to FFFFh(Size=64K),then Can not used it to Access
//4G bytes Memory Again,Because FS is Segment:Offset Memory type after that.
//If Use it to Access large than 64K will generate Execption 0D.
unsigned char ReadByte(unsigned long Address)
{
?? asm db 0x66
?? asm mov di,word ptr Address //MOV EDI,Address
?? asm db 0x67?? //32 bit Address Prefix
?? asm db 0x64?? //FS:
?? asm mov al,byte ptr [BX] //=MOV AL,FS:[EDI]
?? return _AL;
}
unsigned char WriteByte(unsigned long Address)
{
?? asm db 0x66
?? asm mov di,word ptr Address //MOV EDI,Address
?? asm db 0x67?? //32 bit Address Prefix
?? asm db 0x64?? //FS:
?? asm mov byte ptr [BX],al //=MOV FS:[EDI],AL
?? return _AL;
}
/ Don't Touch Above Code ///
#include <stdio.h>
void Dump4G(unsigned long Address)
{
?? int i;
?? int j;
?? for(i=0;i<20;i++)
??? {
??? printf("%08lX: ",(Address+i*16));
??? for(j=0;j<16;j++)
???? printf("%02X ",ReadByte(Address+i*16+j));
??? printf("??????? ");
??? for(j=0;j<16;j++)
???? {
???? if(ReadByte(Address+i*16+j)<0x20) printf(".");
???? else printf("%c",ReadByte(Address+i*16+j));
???? }
??? printf("\n");
??? }
}
main()
{
?? char KeyBuffer[256];
?? unsigned long?? Address=0;
?? unsigned long tmp;
????
?? LoadFSLimit4G();
?? printf("====Designed By Southern.1995.7.17====\n");
?? printf("Now you can Access The Machine All 4G Memory.\n");
?? printf("Input the Start Memory Physical to DUMP.\n");
?? printf("Press D to Cuntinue DUMP,0 to End & Quit.\n");
?? do {
??? printf("-");
??? gets(KeyBuffer);
??? sscanf(KeyBuffer,"%lX",&tmp);
??? if(KeyBuffer[0]=='q') break;
??? if(KeyBuffer[0]=='d') Address+=(20*16);
??? else Address=tmp;
??? Dump4G(Address);
??? }while(Address!=0);
?? return 0;
}
類(lèi)別:Bios?查看評(píng)論
轉(zhuǎn)載于:https://www.cnblogs.com/kuwoyidai/archive/2010/07/14/1777527.html
總結(jié)
以上是生活随笔為你收集整理的DOS下如何访问4G内存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 货币是怎样产生的 货币是怎么产生的
- 下一篇: 酷比魔方平板将适配全新 UI:采用玻璃质