『楼 主』:
谁能详细解释一下下面这段代码?
使用 LLM 解释/回答一下
下面就来告诉大家怎么做到在实模式下访问4GB内存。这种技术需要保护模式支持,所以只能在80386以上的CPU中运行。 学过一点保护模式的读者都知道,在保护模式下段地址寄存器中内容的不再象实模式那样是段的基地址,而只是描述符表中的一个索引,段的真正信息(基地址、限长、访问权限等)放在描述符表中,当访问一数据时CPU会从描述符表取出段的描述信息来检查访问是否合法,不合法就产生异常,合法则允许访问。每次访问都要读出描述符信息再检查是一个比较费时的过程,为了提高内存访问的速度,Intel公司在CPU中为每个段寄存器配备了一个高速缓冲器来存放段的描述符信息,这样访问内存时就不用频繁地访问描述表,只要从高速缓冲进行校验就行,只有在改变段寄存器的值时才访问描述符表将新的段描述符装入高速缓冲中。我们就利用CPU的这个特性来达成我们的目的。首先进入保护模式,把某个段寄存器设为基地址0H,限长4GB,然后再退回实模式。这样就可以通过该段寄存器直接访问4GB的内存了(实际上只能访问你的机器上所有的内存而并不是4GB)!还有一点要注意的是一定要打开A20线,否则……别怪我言之不预!
下面列出所需要的代码:
========================================================
Make4GBSegment MACRO _seg
local MyGdt,PM_Service,Old_GDTR,GDTR,Real_Service,MyGdt
local _Exit
Push DS
Push ES
Pushad
Pushfd ;保护现场
Sub EBX,EBX
Mov BX,CS
Mov DS,BX
Shl EBX,4
Push EBX
Rol EBX,8
Mov BYTE Ptr MyGdt[8+7],BL
Mov BL,BYTE Ptr MyGdt[8+5]
Ror EBX,8
Mov Dword Ptr MyGdt[8+2],EBX
Pop EBX
lea EBX,[EBX+MyGdt]
Mov DWORD Ptr [GDTR+2],EBX
Mov WORD Ptr [GDTR],31 ;建立新的GDTR
Cli
Sgdt FWORD Ptr [Old_GDTR] ;保存旧的GDTR
Lgdt FWORD Ptr [GDTR] ;设置新的GDTR
Mov EBX,CR0
Or BL,1
Mov CR0,EBX ;进入保护模式
db 0eah
DW PM_Service
DW 8 ;跳转到保护模式代码执行
PM_Service:
Mov AX,16
Mov _seg,AX
Mov EBX,CR0
And EBX,0fffffffeh
Mov CR0,EBX
DB 0eah
DW Real_Service
DW seg Real_Service
Real_Service:
Lgdt FWORD Ptr [Old_GDTR]
Popfd ;恢复现场
Popad
Pop ES
Pop DS
Jmp _Exit
MyGdt DQ 0
DW -1,0,9a00h,0
DW -1,0,9200h,0cfh
DQ 0
Old_GDTR DW 0,0,0
GDTR DW 0,0,0
_Exit:
Endm
========================================================
在这里为了方便我只把FS改成4GB段,读者可以按需要自行决定使用哪个段寄存器。只要将这段代码拷贝到你的程序中,然后在开始的时候调用它,就可以通过该段寄存器直接访问大内存了,爽吧!最后还有一点一定要注意:如果你的程序运行时有任何扩展内存管理程序存在(HIMEM、EMM386等)都要千万小心,因为很容易会破坏到它们的内部数据或其他程序的数据,如果是这样就只有死机一条路可走了。切记切记!我的建议是最好从内存顶端开始使用扩展内存。这时破坏其他数据的可能要小一些。
===========================================
这是我找到的一些资料,但是对其中的代码不甚了解,这段程序的作用都已经给出来了,希望能有高人详细解释一番,如果能每行都注释更好 
The following will tell you how to access 4GB memory in real mode. This technology requires the support of protected mode, so it can only run on CPUs above 80386. Readers who have learned a little about protected mode know that the content in the segment address register in protected mode is no longer the base address of the segment like in real mode, but just an index in the descriptor table. The real information of the segment (base address, limit, access rights, etc.) is placed in the descriptor table. When accessing a piece of data, the CPU will take out the segment description information from the descriptor table to check whether the access is legal. If it is illegal, an exception will be generated. If it is legal, access is allowed. Reading the descriptor information and checking each time is a relatively time-consuming process. In order to improve the speed of memory access, Intel has equipped a high-speed buffer for each segment register in the CPU to store the segment descriptor information. In this way, when accessing memory, there is no need to frequently access the descriptor table, and only need to perform verification from the high-speed buffer. Only when the value of the segment register is changed will the descriptor table be accessed to load the new segment descriptor into the high-speed buffer. We use this feature of the CPU to achieve our purpose. First, enter protected mode, set a certain segment register to a base address of 0H and a limit of 4GB, and then return to real mode. In this way, you can directly access 4GB memory through this segment register (actually, you can only access all the memory on your machine, not 4GB)! There is also one thing to note: you must open the A20 line, otherwise... don't blame me for not warning you in advance!
The following lists the required code:
========================================================
Make4GBSegment MACRO _seg
local MyGdt,PM_Service,Old_GDTR,GDTR,Real_Service,MyGdt
local _Exit
Push DS
Push ES
Pushad
Pushfd ; Save the scene
Sub EBX,EBX
Mov BX,CS
Mov DS,BX
Shl EBX,4
Push EBX
Rol EBX,8
Mov BYTE Ptr MyGdt,BL
Mov BL,BYTE Ptr MyGdt
Ror EBX,8
Mov Dword Ptr MyGdt,EBX
Pop EBX
lea EBX,
Mov DWORD Ptr ,EBX
Mov WORD Ptr ,31 ; Establish new GDTR
Cli
Sgdt FWORD Ptr ; Save the old GDTR
Lgdt FWORD Ptr ; Set new GDTR
Mov EBX,CR0
Or BL,1
Mov CR0,EBX ; Enter protected mode
db 0eah
DW PM_Service
DW 8 ; Jump to protected mode code execution
PM_Service:
Mov AX,16
Mov _seg,AX
Mov EBX,CR0
And EBX,0fffffffeh
Mov CR0,EBX
DB 0eah
DW Real_Service
DW seg Real_Service
Real_Service:
Lgdt FWORD Ptr
Popfd ; Restore the scene
Popad
Pop ES
Pop DS
Jmp _Exit
MyGdt DQ 0
DW -1,0,9a00h,0
DW -1,0,9200h,0cfh
DQ 0
Old_GDTR DW 0,0,0
GDTR DW 0,0,0
_Exit:
Endm
========================================================
Here, for the convenience of me, I only change FS to a 4GB segment. You can decide which segment register to use according to your needs. Just copy this code into your program, and then call it at the beginning, and you can directly access large memory through this segment register. Cool, right! Finally, one more thing must be noted: if there are any extended memory management programs (HIMEM, EMM386, etc.) when your program is running, be very careful, because it is very easy to damage their internal data or other programs' data. If this is the case, there is only one way to crash. Remember, remember! My suggestion is to better use extended memory from the top of memory. At this time, the possibility of damaging other data is smaller.
===========================================
These are some materials I found, but I don't understand the code very well. The function of this program has been given. I hope some expert can explain it in detail. It would be better if there are comments for each line :P
|