DOS下如何访问4G内存
從表面上看,保護模式和實模式并沒有太大的區別,二者都使用了內存段、中斷和設備驅動來處理硬件,但二者有很多不同之處。我們知道,在實模式中內存被劃分成段,每個段的大小為64KB,而這樣的段地址可以用16位來表示。內存段的處理是通過和段寄存器相關聯的內部機制來處理的,這些段寄存器(CS、DS、SS和ES)的內容形成了物理地址的一部分。具體來說,最終的物理地址是由16位的段地址和16位的段內偏移地址組成的。用公式表示為:
物理地址=左移4位的段地址+偏移地址。
在保護模式下,段是通過一系列被稱之為“描述符表”的表所定義的。段寄存器存儲的是指向這些表的指針。用于定義內存段的表有兩種:全局描述符表(GDT)和局部描述符表(LDT)。GDT是一個段描述符數組,其中包含所有應用程序都可以使用的基本描述符。在實模式中,段長是固定的(為64KB),而在保護模式中,段長是可變的,其最大可達4GB。LDT也是段描述符的一個數組。與GDT不同,LDT是一個段,其中存放的是局部的、不需要全局共享的段描述符。每一個操作系統都必須定義一個GDT,而每一個正在運行的任務都會有一個相應的LDT。每一個描述符的長度是8個字節,格式如圖3所示。當段寄存器被加載的時候,段基地址就會從相應的表入口獲得。描述符的內容會被存儲在一個程序員不可見的影像寄存器(shadow register)之中,以便下一次同一個段可以使用該信息而不用每次都到表中提取。物理地址由16位或者32位的偏移加上影像寄存器中的基址組成。實模式和保護模式的不同可以從圖1和圖2中很清楚地看出來。
此外,還有一個中斷描述符表(IDT)。這些中斷描述符會告訴處理器到那里可以找到中斷處理程序。和實模式一樣,每一個中斷都有一個入口,但是這些入口的格式卻完全不同。因為在切換到保護模式的過程中沒有使用到IDT,所以在此就不多做介紹了。 2.GDT表 關于GDT表,你可以這樣理解:就是一串連續的變量.變量的大小是8字節.而每一位均代表不同的意義,相關的說明可以看一下其它的教程,都有詳細的解釋.其中第一個八字節變量必需保留,其值應該為0.這里的每個變量(除了第一個保留變量)都定義了一個段,并描述出了這個段的起始位置,大小,屬性等.
接下去介紹如何進入保護模式 可以分為以下幾個步驟: a.創建GDT表;
b.通過置PE位為1進入保護模式;
c.執行跳轉以清除在實模式下讀取的任何指令。 然后給出一個進保護模式的具體例子:(匯編)
[BITS 16]
[ORG 0x8000]
jmp main
;∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑
;GDT定義.
;代碼段及數據段整合.占用整個內存.
;∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑∑
GDT:
GdtNULL:
dw 0x0000
dw 0x0000
dw 0x0000
dw 0x0000
GdtCode:
dw 0xffff
dw 0x0000
dw 0x9a00 ;a為Type表示,執行,只讀
dw 0x00cf
GdtData:
dw 0xffff
dw 0x0000
dw 0x9200 ;2為Type表示,讀/寫
dw 0x00cf
GdtReg dw GdtReg-GDT-1
dd GDT
SelCode equ GdtCode-GDT
SelData equ GdtData-GDT
;-------------------GDT定義結束--------------------
main: ;內核跳轉時將跳轉地址賦予bx
?? xor ax,ax
?? mov ds,ax
?? cli
?? lgdt [GdtReg]
?? sti
?? in al,92h ;打開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下訪問4G memory的具體c語言代碼如下:(BC3.1編譯通過,386平臺)
#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;
}
類別:Bios?查看評論
轉載于:https://www.cnblogs.com/kuwoyidai/archive/2010/07/14/1777527.html
總結
以上是生活随笔為你收集整理的DOS下如何访问4G内存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 货币是怎样产生的 货币是怎么产生的
- 下一篇: 我的“网管工具箱”