#include "dos.h"
#include "stdio.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
};
unsigned char OldIDT [6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp [6]={0}; //NULL The IDTR s Limit=0 CPU 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.
//*** Lodd GDTR //***
asm{ // The right Code is Real, But BC++ s Linker NOT Work with 32bits 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 low16 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 //****
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 CRO,EAX // Set Protection enable bit//执行这句也会重启
//JMP flush//
} //Clear machine perform cache.
// Now In Flat Mode, But The CS is Real Mode value.
//flush:
asm{ //And it s attrib is 16Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX
//Load FS Base=0 Size=4G now
db 0x66,0x0F,0x22,0xC0 //MOV CRO,EAX
//Return Real Mode.
LIDT OldIDT //LIDT OldIDT //Restore IDTR //这句也重启
STI // STI //Enable INTR
}
}
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 ax,word ptr [BX] // =MOV AL, FS: [EDI]
return _AX;
}
void WriteByte(unsigned long Address, unsigned short data)
{
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 ax,data
asm mov word ptr [BX],ax
}
void main(void)
{
LoadFSLimit4G();
unsigned long addr;
unsigned short rtn0,rtn1;
unsigned short data;
data = 100;
addr = 0x00100000;
rtn0 = ReadByte(addr);
addr = 0x00110000;
WriteByte(addr,data);
rtn1 = ReadByte(addr);
addr = 0x00100000;
rtn0 = ReadByte(addr);
}
25 个解决方案
#1
知道的帮个忙~~~
在线等~~~
在线等~~~
#2
既然是实模式,执行LIDT干什么?切入保护模式装入描述符后就切回实模式。
#3
好像是切入保护模式前保存IDTR值,退出保护模式后还要恢复。
我如果不加LIDT这一句,曾经成功运行过,但是读回来的值并不对,而且往一个地址写值后,读其他地址的值竟然都变成这个值,很奇怪啊
其实对保护模式并不是很了解,只是现在需要用到DOS下读取高于1M的内存,才找了一些相关资料参考,很多东西都不是很了解,大家多多指教。
我如果不加LIDT这一句,曾经成功运行过,但是读回来的值并不对,而且往一个地址写值后,读其他地址的值竟然都变成这个值,很奇怪啊
其实对保护模式并不是很了解,只是现在需要用到DOS下读取高于1M的内存,才找了一些相关资料参考,很多东西都不是很了解,大家多多指教。
#4
“在DOS实模式下直接存取4G内存”不需要IDT,只要一个GDT,其中含有一个有效的描述符,程序开A20、关中断、切保护模式、给ds、es等装入描述符、返回实模式、开中断,这样就行了。
#5
cnzdgs,我已经按你说的步骤重新改了个程序,可是还有两个问题:
1.写内存的时候如果直接运行就会自动跳出程序,只能重启,单步的话就没有问题
2.读内存的值好像还是不对,而且往一个地址写值后,读取其他地址的值就都变成一样的,麻烦你帮我看看吧。。。
代码如下:
//打开A20
void openA20()
{
while(inp(0x64) & 2); outp(0x64,0xd1);
while(inp(0x64) & 2); outp(0x60,0xdf);
while(inp(0x64) & 2); outp(0x64,0xff);
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
void write_ram(unsigned long addr,unsigned short chr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,chr
asm mov word ptr [bx],ax//asm mov [esi],al
asm pop ds
}
void main(void)
{
openA20();
set4gb();
unsigned long addr = 0xD0100000;
unsigned short data = 0x12;
unsigned short rtn0,rtn1;
addr = 0x00100000;
rtn0 = read_ram(addr);
addr = 0xD0100000;
rtn0 = read_ram(addr);
write_ram(addr,data);
rtn1 = read_ram(addr);
addr = 0x00100000;
rtn0 = read_ram(addr);
return;
}
1.写内存的时候如果直接运行就会自动跳出程序,只能重启,单步的话就没有问题
2.读内存的值好像还是不对,而且往一个地址写值后,读取其他地址的值就都变成一样的,麻烦你帮我看看吧。。。
代码如下:
//打开A20
void openA20()
{
while(inp(0x64) & 2); outp(0x64,0xd1);
while(inp(0x64) & 2); outp(0x60,0xdf);
while(inp(0x64) & 2); outp(0x64,0xff);
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
void write_ram(unsigned long addr,unsigned short chr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,chr
asm mov word ptr [bx],ax//asm mov [esi],al
asm pop ds
}
void main(void)
{
openA20();
set4gb();
unsigned long addr = 0xD0100000;
unsigned short data = 0x12;
unsigned short rtn0,rtn1;
addr = 0x00100000;
rtn0 = read_ram(addr);
addr = 0xD0100000;
rtn0 = read_ram(addr);
write_ram(addr,data);
rtn1 = read_ram(addr);
addr = 0x00100000;
rtn0 = read_ram(addr);
return;
}
#6
GDT_def要包含两个描述符,第1个全0,第2个才是要用的。
#7
不好意思,我没懂,那要如何定义?
#8
原来的代码好像没有什么问题,
你是在windows下运行BC++然后调试你的程序么?还是在纯DOS下
如果是windows的话,重启是正常的.因为windows下是保护模式.windows下那个cmd是32位的,16位command.com之类的老DOS程序是运行在虚拟8086模式.
我曾在windows下调试类似的代码每次都不行,最后在纯dos下(我用的是dos7.1)或者虚拟机里面的纯dos,都可以通过.
另外,如果你用的是BC++,BC++的内联汇编好像只支持286的,不支持32位的.
但BC++3.0自带TASM的,可以使用fs,eax,cr0等等.可以在IDE里面编调试汇编.
建一个工程,把带有main函数的C文件加进去,在把asm文件加进去,build一下就可以了,
也可以不用C,纯用汇编来写,要自己定义一个_main proc.最好还是加入到工程里面build,单个asm编译有时候会出问题.
你是在windows下运行BC++然后调试你的程序么?还是在纯DOS下
如果是windows的话,重启是正常的.因为windows下是保护模式.windows下那个cmd是32位的,16位command.com之类的老DOS程序是运行在虚拟8086模式.
我曾在windows下调试类似的代码每次都不行,最后在纯dos下(我用的是dos7.1)或者虚拟机里面的纯dos,都可以通过.
另外,如果你用的是BC++,BC++的内联汇编好像只支持286的,不支持32位的.
但BC++3.0自带TASM的,可以使用fs,eax,cr0等等.可以在IDE里面编调试汇编.
建一个工程,把带有main函数的C文件加进去,在把asm文件加进去,build一下就可以了,
也可以不用C,纯用汇编来写,要自己定义一个_main proc.最好还是加入到工程里面build,单个asm编译有时候会出问题.
#9
我是在纯DOS下,BC31调试程序的,在advanced code generation 里面已经选择了386模式
而且为了让DOS实模式下的16位程序可用32位寄存器和地址,在代码中加入操作码前缀0x66和地址前缀0x67,所以应该没有问题了。
但是结果就是不对,很郁闷啊
而且为了让DOS实模式下的16位程序可用32位寄存器和地址,在代码中加入操作码前缀0x66和地址前缀0x67,所以应该没有问题了。
但是结果就是不对,很郁闷啊
#10
cs!=0(gdt)
cs=0(是null不是gdt0)
cs=0(是null不是gdt0)
#11
哦,我看了一下面的代码,
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字 //设置了,怎么没有加载?
db 0x8E,0xE2 //MOV FS,DX 跟前面一样,把段地址放在FS寄存器里
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
//asm mov ax,0
asm mov ds,ax //这样不行的吧.实模式16位的赋值,还是用FS好
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字 //设置了,怎么没有加载?
db 0x8E,0xE2 //MOV FS,DX 跟前面一样,把段地址放在FS寄存器里
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
//asm mov ax,0
asm mov ds,ax //这样不行的吧.实模式16位的赋值,还是用FS好
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
#12
加载了选择字后,往一个地址写值后,别的地址不会被改写了,但是好像有时候写成功了,有时候失败了,读回来仍然是0
直接运行write_ram还是会自动跳出程序死机,单步就没问题,搞不懂为什么
Crazii,我按你的建议改城如下程序:
unsigned char read_ram (unsigned long addr)
{
asm db 0x66
asm mov di,word ptr addr // MOV EDI, addr
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
return _AX;
}
也死机了。。。
直接运行write_ram还是会自动跳出程序死机,单步就没问题,搞不懂为什么
Crazii,我按你的建议改城如下程序:
unsigned char read_ram (unsigned long addr)
{
asm db 0x66
asm mov di,word ptr addr // MOV EDI, addr
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
return _AX;
}
也死机了。。。
#13
单步的话倒是不会死机,但也是写了值,所有的地址读回来又都是这个值
#14
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
前面是把32位线性地址给edi了吧,这里应该用edi
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [di]
前面是把32位线性地址给edi了吧,这里应该用edi
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [di]
#15
还是不对啊。。。不知道是哪里出了问题。。。。
#16
哦?无语..还有问题啊.目前是什么情况.更严重了..?..
#17
呵呵,我也无语了
现在情况跟之前差不多,直接执行读写就死机,单步可以通过
如果对一个地址写了值,读回来是对的,但是读其他地址也都是这个值了。。。
(现在还没有管到底写对地方没有)
现在情况跟之前差不多,直接执行读写就死机,单步可以通过
如果对一个地址写了值,读回来是对的,但是读其他地址也都是这个值了。。。
(现在还没有管到底写对地方没有)
#18
你退出IDE,在DOS下运行,试试~~
我再看看代码..
我再看看代码..
#19
天 啊
#20
退出IDE,直接运行,就没反应了
#21
我用第一楼的代码,去掉LDT之后,该了一个错误(见红色部分),运行通过.
退出IDE之后,最好先cls清屏,防止滚屏,然后运行程序,屏幕最上方会显示一个A,说明32位地址已经有效了.程序正常结束
不过我真的受不了那个0x66,0x67.等等的那些前缀......
#include "dos.h "
#include "stdio.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
};
//unsigned char OldIDT [6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp [6]={0}; //NULL The IDTR s Limit=0 CPU 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.
//*** Lodd GDTR //***
asm{ // The right Code is Real, But BC++ s Linker NOT Work with 32bits 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 low16 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 //****
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 CRO,EAX // Set Protection enable bit//执行这句也会重启
//JMP flush//
} //Clear machine perform cache.
// Now In Flat Mode, But The CS is Real Mode value.
//flush:
asm{ //And it s attrib is 16Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX
//Load FS Base=0 Size=4G now
db 0x66,0x0F,0x22,0xC0 //MOV CRO,EAX
//Return Real Mode.
//LIDT OldIDT //LIDT OldIDT //Restore IDTR //这句也重启
STI // STI //Enable INTR
}
}
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 ax,word ptr [bx] // =MOV AL, FS: [EDI] //这一句我不懂,bx寄存器,加了前面两个字节的指令前缀,就变成edi了....但貌似是正确的.
return _AX;
}
void WriteByte(unsigned long Address, unsigned short data)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI, Address
asm mov ax,data //把这一句放在前面,因为下面的指令前缀是针对最后一句写内存指令的,而不是本句
//另外,这里要访问data,默认是ds:data,所以在这个函数里面不要修改ds的值,否则访问不到正确的数据
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS
asm mov word ptr [bx],ax
}
void main(void)
{
unsigned long addr;
unsigned short rtn0,rtn1;
unsigned short data;
LoadFSLimit4G();
data = 0x4141;//第一个41是颜色属性,第二个0x41是'A'
addr = 0x00100000;
rtn0 = ReadByte(addr);
addr = 0x000b8000; //写显存b800:0000 (16位分段的地址)= b8000(32位线性地址)
WriteByte(addr,data);
rtn1 = ReadByte(addr);
addr = 0x00100000;
rtn0 = ReadByte(addr);
}
退出IDE之后,最好先cls清屏,防止滚屏,然后运行程序,屏幕最上方会显示一个A,说明32位地址已经有效了.程序正常结束
不过我真的受不了那个0x66,0x67.等等的那些前缀......
#include "dos.h "
#include "stdio.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
};
//unsigned char OldIDT [6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp [6]={0}; //NULL The IDTR s Limit=0 CPU 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.
//*** Lodd GDTR //***
asm{ // The right Code is Real, But BC++ s Linker NOT Work with 32bits 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 low16 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 //****
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 CRO,EAX // Set Protection enable bit//执行这句也会重启
//JMP flush//
} //Clear machine perform cache.
// Now In Flat Mode, But The CS is Real Mode value.
//flush:
asm{ //And it s attrib is 16Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX
//Load FS Base=0 Size=4G now
db 0x66,0x0F,0x22,0xC0 //MOV CRO,EAX
//Return Real Mode.
//LIDT OldIDT //LIDT OldIDT //Restore IDTR //这句也重启
STI // STI //Enable INTR
}
}
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 ax,word ptr [bx] // =MOV AL, FS: [EDI] //这一句我不懂,bx寄存器,加了前面两个字节的指令前缀,就变成edi了....但貌似是正确的.
return _AX;
}
void WriteByte(unsigned long Address, unsigned short data)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI, Address
asm mov ax,data //把这一句放在前面,因为下面的指令前缀是针对最后一句写内存指令的,而不是本句
//另外,这里要访问data,默认是ds:data,所以在这个函数里面不要修改ds的值,否则访问不到正确的数据
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS
asm mov word ptr [bx],ax
}
void main(void)
{
unsigned long addr;
unsigned short rtn0,rtn1;
unsigned short data;
LoadFSLimit4G();
data = 0x4141;//第一个41是颜色属性,第二个0x41是'A'
addr = 0x00100000;
rtn0 = ReadByte(addr);
addr = 0x000b8000; //写显存b800:0000 (16位分段的地址)= b8000(32位线性地址)
WriteByte(addr,data);
rtn1 = ReadByte(addr);
addr = 0x00100000;
rtn0 = ReadByte(addr);
}
#22
太感动了,非常非常的感谢~~~~
我去试试看
我去试试看
#23
可以了,太谢谢了,困扰了我N久的问题。。。。。都快烦死了
谢谢~~~~
不过有点不明白,怎么它全速运行和单步运行得到的结果会不一样呢???
如果用F8执行就压根过不去,这是为什么啊?
谢谢~~~~
不过有点不明白,怎么它全速运行和单步运行得到的结果会不一样呢???
如果用F8执行就压根过不去,这是为什么啊?
#24
我也不知道啊,直接Ctrl+F9可以运行的,但是单步跟踪就死了.
估计是因为bc的turbo debugger是实模式下的调试器吧,保护模式下可能会出错,跟踪不了...不清楚
估计是因为bc的turbo debugger是实模式下的调试器吧,保护模式下可能会出错,跟踪不了...不清楚
#25
又碰到了一个问题。。。。
发现每次读取内存的时候,只有最开始一两次读的是对的,后面的就都错了,搞不明白为什么?
发现每次读取内存的时候,只有最开始一两次读的是对的,后面的就都错了,搞不明白为什么?
#1
知道的帮个忙~~~
在线等~~~
在线等~~~
#2
既然是实模式,执行LIDT干什么?切入保护模式装入描述符后就切回实模式。
#3
好像是切入保护模式前保存IDTR值,退出保护模式后还要恢复。
我如果不加LIDT这一句,曾经成功运行过,但是读回来的值并不对,而且往一个地址写值后,读其他地址的值竟然都变成这个值,很奇怪啊
其实对保护模式并不是很了解,只是现在需要用到DOS下读取高于1M的内存,才找了一些相关资料参考,很多东西都不是很了解,大家多多指教。
我如果不加LIDT这一句,曾经成功运行过,但是读回来的值并不对,而且往一个地址写值后,读其他地址的值竟然都变成这个值,很奇怪啊
其实对保护模式并不是很了解,只是现在需要用到DOS下读取高于1M的内存,才找了一些相关资料参考,很多东西都不是很了解,大家多多指教。
#4
“在DOS实模式下直接存取4G内存”不需要IDT,只要一个GDT,其中含有一个有效的描述符,程序开A20、关中断、切保护模式、给ds、es等装入描述符、返回实模式、开中断,这样就行了。
#5
cnzdgs,我已经按你说的步骤重新改了个程序,可是还有两个问题:
1.写内存的时候如果直接运行就会自动跳出程序,只能重启,单步的话就没有问题
2.读内存的值好像还是不对,而且往一个地址写值后,读取其他地址的值就都变成一样的,麻烦你帮我看看吧。。。
代码如下:
//打开A20
void openA20()
{
while(inp(0x64) & 2); outp(0x64,0xd1);
while(inp(0x64) & 2); outp(0x60,0xdf);
while(inp(0x64) & 2); outp(0x64,0xff);
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
void write_ram(unsigned long addr,unsigned short chr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,chr
asm mov word ptr [bx],ax//asm mov [esi],al
asm pop ds
}
void main(void)
{
openA20();
set4gb();
unsigned long addr = 0xD0100000;
unsigned short data = 0x12;
unsigned short rtn0,rtn1;
addr = 0x00100000;
rtn0 = read_ram(addr);
addr = 0xD0100000;
rtn0 = read_ram(addr);
write_ram(addr,data);
rtn1 = read_ram(addr);
addr = 0x00100000;
rtn0 = read_ram(addr);
return;
}
1.写内存的时候如果直接运行就会自动跳出程序,只能重启,单步的话就没有问题
2.读内存的值好像还是不对,而且往一个地址写值后,读取其他地址的值就都变成一样的,麻烦你帮我看看吧。。。
代码如下:
//打开A20
void openA20()
{
while(inp(0x64) & 2); outp(0x64,0xd1);
while(inp(0x64) & 2); outp(0x60,0xdf);
while(inp(0x64) & 2); outp(0x64,0xff);
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
void write_ram(unsigned long addr,unsigned short chr)
{ asm push ds
asm mov ax,0
asm mov ds,ax
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,chr
asm mov word ptr [bx],ax//asm mov [esi],al
asm pop ds
}
void main(void)
{
openA20();
set4gb();
unsigned long addr = 0xD0100000;
unsigned short data = 0x12;
unsigned short rtn0,rtn1;
addr = 0x00100000;
rtn0 = read_ram(addr);
addr = 0xD0100000;
rtn0 = read_ram(addr);
write_ram(addr,data);
rtn1 = read_ram(addr);
addr = 0x00100000;
rtn0 = read_ram(addr);
return;
}
#6
GDT_def要包含两个描述符,第1个全0,第2个才是要用的。
#7
不好意思,我没懂,那要如何定义?
#8
原来的代码好像没有什么问题,
你是在windows下运行BC++然后调试你的程序么?还是在纯DOS下
如果是windows的话,重启是正常的.因为windows下是保护模式.windows下那个cmd是32位的,16位command.com之类的老DOS程序是运行在虚拟8086模式.
我曾在windows下调试类似的代码每次都不行,最后在纯dos下(我用的是dos7.1)或者虚拟机里面的纯dos,都可以通过.
另外,如果你用的是BC++,BC++的内联汇编好像只支持286的,不支持32位的.
但BC++3.0自带TASM的,可以使用fs,eax,cr0等等.可以在IDE里面编调试汇编.
建一个工程,把带有main函数的C文件加进去,在把asm文件加进去,build一下就可以了,
也可以不用C,纯用汇编来写,要自己定义一个_main proc.最好还是加入到工程里面build,单个asm编译有时候会出问题.
你是在windows下运行BC++然后调试你的程序么?还是在纯DOS下
如果是windows的话,重启是正常的.因为windows下是保护模式.windows下那个cmd是32位的,16位command.com之类的老DOS程序是运行在虚拟8086模式.
我曾在windows下调试类似的代码每次都不行,最后在纯dos下(我用的是dos7.1)或者虚拟机里面的纯dos,都可以通过.
另外,如果你用的是BC++,BC++的内联汇编好像只支持286的,不支持32位的.
但BC++3.0自带TASM的,可以使用fs,eax,cr0等等.可以在IDE里面编调试汇编.
建一个工程,把带有main函数的C文件加进去,在把asm文件加进去,build一下就可以了,
也可以不用C,纯用汇编来写,要自己定义一个_main proc.最好还是加入到工程里面build,单个asm编译有时候会出问题.
#9
我是在纯DOS下,BC31调试程序的,在advanced code generation 里面已经选择了386模式
而且为了让DOS实模式下的16位程序可用32位寄存器和地址,在代码中加入操作码前缀0x66和地址前缀0x67,所以应该没有问题了。
但是结果就是不对,很郁闷啊
而且为了让DOS实模式下的16位程序可用32位寄存器和地址,在代码中加入操作码前缀0x66和地址前缀0x67,所以应该没有问题了。
但是结果就是不对,很郁闷啊
#10
cs!=0(gdt)
cs=0(是null不是gdt0)
cs=0(是null不是gdt0)
#11
哦,我看了一下面的代码,
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字 //设置了,怎么没有加载?
db 0x8E,0xE2 //MOV FS,DX 跟前面一样,把段地址放在FS寄存器里
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
//asm mov ax,0
asm mov ds,ax //这样不行的吧.实模式16位的赋值,还是用FS好
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
unsigned long GDT_def[]={0,0,0x0000FFFF,0x008F9200}; //全局描述符表GDT
unsigned char GDT_Addr[6]={0}; //存放GDT的基地址和长度
void set4gb()
{ asm{
cli//disable interrupt
push ds ; push es
mov word ptr GDT_Addr[0], (2*8-1) //GDT的长度存入GDT_Addr中
db 0x66
mov ax,ds//mov eax,ds //计算GDT描述符表的线性基地址31-0
db 0x66
shl ax,4//shl eax,4 //段地址eax=ds×16
db 0x66
xor bx,bx//xor ebx,ebx //ebx清零
mov bx,offset GDT_def //bx=GDT的偏移地址
db 0x66
add ax,bx//add eax,ebx //GDT的线性基地址=eax+ebx
mov word ptr GDT_Addr[2],ax
db 0x66
shr ax,16
mov word ptr GDT_Addr[4],ax
lgdt GDT_Addr
//mov dword ptr GDT_Addr[2],eax //GDT的线性基地址存入GDT_Addr中
//lgdt fword ptr GDT_Addr
mov bx,8 //设置数据段描述符的选择字 //设置了,怎么没有加载?
db 0x8E,0xE2 //MOV FS,DX 跟前面一样,把段地址放在FS寄存器里
db 0x66,0x0f,0x20,0xc0//mov eax,cr0
or al,1//????
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush1
} //进入保护方式
flush1: asm{
mov ds,bx //DS装载具有4GB界限的数据段描述符
mov es,bx //ES装载具有4GB界限的数据段描述符
and al,0feh
db 0x66,0x0f,0x22,0xc0//mov cr0,eax
jmp flush2
} //返回实方式
flush2: asm{
pop es ; pop ds
sti
}
}
unsigned short read_ram(unsigned long addr)
{ asm push ds
//asm mov ax,0
asm mov ds,ax //这样不行的吧.实模式16位的赋值,还是用FS好
asm db 0x66
asm mov si,word ptr addr//asm mov esi,addr
asm db 0x67
asm db 0x64
asm mov ax,word ptr [bx]//
//asm mov al,[esi]
asm pop ds
return _AX;
}
#12
加载了选择字后,往一个地址写值后,别的地址不会被改写了,但是好像有时候写成功了,有时候失败了,读回来仍然是0
直接运行write_ram还是会自动跳出程序死机,单步就没问题,搞不懂为什么
Crazii,我按你的建议改城如下程序:
unsigned char read_ram (unsigned long addr)
{
asm db 0x66
asm mov di,word ptr addr // MOV EDI, addr
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
return _AX;
}
也死机了。。。
直接运行write_ram还是会自动跳出程序死机,单步就没问题,搞不懂为什么
Crazii,我按你的建议改城如下程序:
unsigned char read_ram (unsigned long addr)
{
asm db 0x66
asm mov di,word ptr addr // MOV EDI, addr
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
return _AX;
}
也死机了。。。
#13
单步的话倒是不会死机,但也是写了值,所有的地址读回来又都是这个值
#14
asm mov ax,word ptr [BX] // =MOV AL, FS: [EDI]
前面是把32位线性地址给edi了吧,这里应该用edi
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [di]
前面是把32位线性地址给edi了吧,这里应该用edi
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS:
asm mov ax,word ptr [di]
#15
还是不对啊。。。不知道是哪里出了问题。。。。
#16
哦?无语..还有问题啊.目前是什么情况.更严重了..?..
#17
呵呵,我也无语了
现在情况跟之前差不多,直接执行读写就死机,单步可以通过
如果对一个地址写了值,读回来是对的,但是读其他地址也都是这个值了。。。
(现在还没有管到底写对地方没有)
现在情况跟之前差不多,直接执行读写就死机,单步可以通过
如果对一个地址写了值,读回来是对的,但是读其他地址也都是这个值了。。。
(现在还没有管到底写对地方没有)
#18
你退出IDE,在DOS下运行,试试~~
我再看看代码..
我再看看代码..
#19
天 啊
#20
退出IDE,直接运行,就没反应了
#21
我用第一楼的代码,去掉LDT之后,该了一个错误(见红色部分),运行通过.
退出IDE之后,最好先cls清屏,防止滚屏,然后运行程序,屏幕最上方会显示一个A,说明32位地址已经有效了.程序正常结束
不过我真的受不了那个0x66,0x67.等等的那些前缀......
#include "dos.h "
#include "stdio.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
};
//unsigned char OldIDT [6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp [6]={0}; //NULL The IDTR s Limit=0 CPU 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.
//*** Lodd GDTR //***
asm{ // The right Code is Real, But BC++ s Linker NOT Work with 32bits 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 low16 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 //****
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 CRO,EAX // Set Protection enable bit//执行这句也会重启
//JMP flush//
} //Clear machine perform cache.
// Now In Flat Mode, But The CS is Real Mode value.
//flush:
asm{ //And it s attrib is 16Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX
//Load FS Base=0 Size=4G now
db 0x66,0x0F,0x22,0xC0 //MOV CRO,EAX
//Return Real Mode.
//LIDT OldIDT //LIDT OldIDT //Restore IDTR //这句也重启
STI // STI //Enable INTR
}
}
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 ax,word ptr [bx] // =MOV AL, FS: [EDI] //这一句我不懂,bx寄存器,加了前面两个字节的指令前缀,就变成edi了....但貌似是正确的.
return _AX;
}
void WriteByte(unsigned long Address, unsigned short data)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI, Address
asm mov ax,data //把这一句放在前面,因为下面的指令前缀是针对最后一句写内存指令的,而不是本句
//另外,这里要访问data,默认是ds:data,所以在这个函数里面不要修改ds的值,否则访问不到正确的数据
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS
asm mov word ptr [bx],ax
}
void main(void)
{
unsigned long addr;
unsigned short rtn0,rtn1;
unsigned short data;
LoadFSLimit4G();
data = 0x4141;//第一个41是颜色属性,第二个0x41是'A'
addr = 0x00100000;
rtn0 = ReadByte(addr);
addr = 0x000b8000; //写显存b800:0000 (16位分段的地址)= b8000(32位线性地址)
WriteByte(addr,data);
rtn1 = ReadByte(addr);
addr = 0x00100000;
rtn0 = ReadByte(addr);
}
退出IDE之后,最好先cls清屏,防止滚屏,然后运行程序,屏幕最上方会显示一个A,说明32位地址已经有效了.程序正常结束
不过我真的受不了那个0x66,0x67.等等的那些前缀......
#include "dos.h "
#include "stdio.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
};
//unsigned char OldIDT [6]={0}; //Save The IDTR before Enter Protect Mode.
unsigned char pdescr_tmp [6]={0}; //NULL The IDTR s Limit=0 CPU 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.
//*** Lodd GDTR //***
asm{ // The right Code is Real, But BC++ s Linker NOT Work with 32bits 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 low16 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 //****
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 CRO,EAX // Set Protection enable bit//执行这句也会重启
//JMP flush//
} //Clear machine perform cache.
// Now In Flat Mode, But The CS is Real Mode value.
//flush:
asm{ //And it s attrib is 16Bit Code Segment.
db 0x66
MOV AX,BX //MOV EAX,EBX
db 0x8E,0xE2 //MOV FS,DX
//Load FS Base=0 Size=4G now
db 0x66,0x0F,0x22,0xC0 //MOV CRO,EAX
//Return Real Mode.
//LIDT OldIDT //LIDT OldIDT //Restore IDTR //这句也重启
STI // STI //Enable INTR
}
}
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 ax,word ptr [bx] // =MOV AL, FS: [EDI] //这一句我不懂,bx寄存器,加了前面两个字节的指令前缀,就变成edi了....但貌似是正确的.
return _AX;
}
void WriteByte(unsigned long Address, unsigned short data)
{
asm db 0x66
asm mov di,word ptr Address //MOV EDI, Address
asm mov ax,data //把这一句放在前面,因为下面的指令前缀是针对最后一句写内存指令的,而不是本句
//另外,这里要访问data,默认是ds:data,所以在这个函数里面不要修改ds的值,否则访问不到正确的数据
asm db 0x67 //32 bit Address Prefix
asm db 0x64 //FS
asm mov word ptr [bx],ax
}
void main(void)
{
unsigned long addr;
unsigned short rtn0,rtn1;
unsigned short data;
LoadFSLimit4G();
data = 0x4141;//第一个41是颜色属性,第二个0x41是'A'
addr = 0x00100000;
rtn0 = ReadByte(addr);
addr = 0x000b8000; //写显存b800:0000 (16位分段的地址)= b8000(32位线性地址)
WriteByte(addr,data);
rtn1 = ReadByte(addr);
addr = 0x00100000;
rtn0 = ReadByte(addr);
}
#22
太感动了,非常非常的感谢~~~~
我去试试看
我去试试看
#23
可以了,太谢谢了,困扰了我N久的问题。。。。。都快烦死了
谢谢~~~~
不过有点不明白,怎么它全速运行和单步运行得到的结果会不一样呢???
如果用F8执行就压根过不去,这是为什么啊?
谢谢~~~~
不过有点不明白,怎么它全速运行和单步运行得到的结果会不一样呢???
如果用F8执行就压根过不去,这是为什么啊?
#24
我也不知道啊,直接Ctrl+F9可以运行的,但是单步跟踪就死了.
估计是因为bc的turbo debugger是实模式下的调试器吧,保护模式下可能会出错,跟踪不了...不清楚
估计是因为bc的turbo debugger是实模式下的调试器吧,保护模式下可能会出错,跟踪不了...不清楚
#25
又碰到了一个问题。。。。
发现每次读取内存的时候,只有最开始一两次读的是对的,后面的就都错了,搞不明白为什么?
发现每次读取内存的时候,只有最开始一两次读的是对的,后面的就都错了,搞不明白为什么?