DOS下读取4GB内存——梁肇新代码分析
程序原理:
?
CPU上電后,從ROM 中的BIOS開始運行。
BIOS是處在內存的最頂端64KB(FFFF0000H),還是1MB之下的64KB(F0000H)處呢?事實上,BIOS在這兩個地方都同時出現。
在保護模式時,CS是08H的選擇子,到了實模式時,CS還是08H,但地址不會突然變成80H加上偏移量。
也就是說,實模式與0特權級保護模式不分頁時是一模一樣的。
所以,實模式下一樣可以處理通常被認為只有在保護模式才能做的事,比如訪問整個機器的內存。
實際上,Intel本身就在使用這種辦法,使得CPU上電時能從FFFFFFF0H處開始第一條指令。
程序功能:
程序執行過程:
程序運行后,等用戶從鍵盤輸入一個字符。
當輸入“Q”字符時,整個程序將退出;
當輸入“D”時,將在屏幕上顯示一屏內存的數據:
最左邊為絕對地址,其后一列顯示的是以十六進制位表示的內存的數據,后一列是數據所對應的ASCII碼。
代碼關鍵分析:
?
(1)IP=0000FFF0H
?
CS∶EIP等于FFFFFFF0H。
?
(2)段寄存器FS在實模式下無法裝入4GB的地址和權限。
所以讓CPU進入一會兒保護模式,在裝入了FS之后馬上回到實模式。
?
保護模式進入方式:建好GDT,把CR0寄存器的位0置上1。
把一個包含有4GB地址空間的值裝入FS之后,就可返回實模式。
?
(3)預先可建好GDT如下:
?
unsigned long GDT-Table[]=
{
0,0,??????????????????? ??? //空描述符,必須為零
0x0000FFFF,0xCF9A00,??? ??? //32位平面式代碼段
0x0000FFFF,0xCF9200 ? ? ? ? //32位平面式數據段
} ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
(4)進入保護模式時要關閉所有的中斷:把IDTR的界限設置為0,CPU自動關閉所有中斷,包括NMI。
返回實模式后恢復IDTR并開中斷。
?
(5)A20地址線的控制對于正確訪問整個內存也很重要。
在進入保護模式前,要讓8042打開A20地址線,否則會出現4GB內存中的混亂。
(6)此程序用BC 3.1編譯連接,其連接器不能為DOS程序處理32位寄存器,所以直接在代碼中加入操作碼前綴0x66和地址前綴0x67,以便讓DOS實模式下的16位程序可用32位寄存器和地址。程序的右邊以注釋形式給出等效的32位指令。
?
注意:16位的指令中,mov al, byte ptr [BX]的指令碼正好是32位的指令mov al, byte ptr[EDI]。
?
附代碼:
#include <dos.h>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
};
//Save The IDTR before Enter Protect Mode.
unsigned char OldIDT[6]={0};
//NULL The IDTR,IDTR's Limit=0 will disable all
//Interrupts,include NMI.
unsigned char pdescr_tmp[6]={0};
#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>
/
//打印出Address指向的內存中的數據
///
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");
}
}
int main( void )
{
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;
}
轉載于:https://www.cnblogs.com/gengzhikui/archive/2011/12/15/2288605.html
總結
以上是生活随笔為你收集整理的DOS下读取4GB内存——梁肇新代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mp4 组成原理
- 下一篇: 电脑操作最忌讳的十八个小动作