<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Unreal_Mode</id>
	<title>Unreal Mode - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Unreal_Mode"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Unreal_Mode&amp;action=history"/>
	<updated>2026-04-04T12:12:34Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Unreal_Mode&amp;diff=1178&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“'''Unreal mode(“非实模式)'''包括通过调整描述符缓存来打破实模式段的64KiB限制（同时保留16位指令和&lt;tt&gt;段*16+偏移量&lt;tt&gt;寻址模式）。  ==用途== 非实模式通常在以下两种情况下被推荐使用: * 你正在尝试扩展传统的16位DOS程序，以便它可以处理更大的数据，Virtual 8086 Mode和xms都不适合你的需要。 * 你正在尝试加载将在大于640K的32位模式下…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Unreal_Mode&amp;diff=1178&amp;oldid=prev"/>
		<updated>2022-04-23T11:37:41Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“&amp;#039;&amp;#039;&amp;#039;Unreal mode(“非实模式)&amp;#039;&amp;#039;&amp;#039;包括通过调整&lt;a href=&quot;/index.php?title=Descriptor_Cache&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Descriptor Cache（页面不存在）&quot;&gt;描述符缓存&lt;/a&gt;来打破实模式段的64KiB限制（同时保留16位指令和&amp;lt;tt&amp;gt;段*16+偏移量&amp;lt;tt&amp;gt;寻址模式）。  ==用途== 非实模式通常在以下两种情况下被推荐使用: * 你正在尝试扩展传统的16位DOS程序，以便它可以处理更大的数据，&lt;a href=&quot;/index.php?title=Virtual_8086_Mode&quot; title=&quot;Virtual 8086 Mode&quot;&gt;Virtual 8086 Mode&lt;/a&gt;和xms都不适合你的需要。 * 你正在尝试加载将在大于640K的32位模式下…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;'''Unreal mode(“非实模式)'''包括通过调整[[Descriptor Cache|描述符缓存]]来打破实模式段的64KiB限制（同时保留16位指令和&amp;lt;tt&amp;gt;段*16+偏移量&amp;lt;tt&amp;gt;寻址模式）。&lt;br /&gt;
&lt;br /&gt;
==用途==&lt;br /&gt;
非实模式通常在以下两种情况下被推荐使用:&lt;br /&gt;
* 你正在尝试扩展传统的16位DOS程序，以便它可以处理更大的数据，[[Virtual 8086 Mode]]和xms都不适合你的需要。&lt;br /&gt;
* 你正在尝试加载将在大于640K的32位模式下运行的程序(因此你不能将其加载到常规内存中)，并且你还不想费心编写保护模式磁盘驱动程序，但你也希望避免在实模式和保护模式之间切换，以将块从传统内存缓冲区复制到扩展内存中。&lt;br /&gt;
&lt;br /&gt;
如果你没有启用 [[A20 Line]]，你仍然无法完全访问所有物理RAM; 所有 “奇数” 1 MiB块将不可用。&lt;br /&gt;
&lt;br /&gt;
==实现==&lt;br /&gt;
为此，你需要将段寄存器的描述符缓存限制设置为大于64KiB的任何值(通常为完整的4GiB(&amp;lt;tt&amp;gt;0xffffffff&amp;lt;/tt&amp;gt;))。&lt;br /&gt;
&lt;br /&gt;
在保护模式下，段寄存器中的位3-15表示[[GDT|全局描述符表]]的索引。 这就是为什么在下面的代码0x08=1000b中，会得到条目#1（条目#0总是一个空描述符）。&lt;br /&gt;
&lt;br /&gt;
当(在保护模式下)段寄存器被加载了“选择器”时，“段描述符缓存寄存器”被填入描述符值，包括大小Size(或限制limit)。 切换回实模式后，无论16位段寄存器中的值是什么，这些值都不会被修改。 因此，64KiB限制不再有效，32位偏移量可以在实模式下用于实际访问64KiB以上的区域（&amp;lt;tt&amp;gt;段*16 + 32位偏移量&amp;lt;/tt&amp;gt;）。&lt;br /&gt;
&lt;br /&gt;
====大非实模式(Big Unreal Mode)===&lt;br /&gt;
这不会触及CS。 &amp;lt;br /&amp;gt;&lt;br /&gt;
因此，IP不受所有这些影响，代码本身仍被限制在64KiB。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
; 汇编示例&lt;br /&gt;
&lt;br /&gt;
; nasm boot.asm -o boot.bin&lt;br /&gt;
; partcopy boot.bin 0 200 -f0&lt;br /&gt;
&lt;br /&gt;
[ORG 0x7c00]              ; add to offsets&lt;br /&gt;
&lt;br /&gt;
start:   xor ax, ax       ; make it zero&lt;br /&gt;
   mov ds, ax             ; DS=0&lt;br /&gt;
   mov ss, ax             ; stack starts at seg 0&lt;br /&gt;
   mov sp, 0x9c00         ; 2000h past code start, &lt;br /&gt;
                          ; making the stack 7.5k in size&lt;br /&gt;
&lt;br /&gt;
   cli                    ; no interrupts&lt;br /&gt;
   push ds                ; save real mode&lt;br /&gt;
&lt;br /&gt;
   lgdt [gdtinfo]         ; load gdt register&lt;br /&gt;
&lt;br /&gt;
   mov  eax, cr0          ; switch to pmode by&lt;br /&gt;
   or al,1                ; set pmode bit&lt;br /&gt;
   mov  cr0, eax&lt;br /&gt;
&lt;br /&gt;
   jmp $+2                ; tell 386/486 to not crash&lt;br /&gt;
&lt;br /&gt;
   mov  bx, 0x08          ; select descriptor 1&lt;br /&gt;
   mov  ds, bx            ; 8h = 1000b&lt;br /&gt;
&lt;br /&gt;
   and al,0xFE            ; back to realmode&lt;br /&gt;
   mov  cr0, eax          ; by toggling bit again&lt;br /&gt;
&lt;br /&gt;
   pop ds                 ; get back old segment&lt;br /&gt;
   sti&lt;br /&gt;
&lt;br /&gt;
   mov bx, 0x0f01         ; attrib/char of smiley&lt;br /&gt;
   mov eax, 0x0b8000      ; note 32 bit offset&lt;br /&gt;
   mov word [ds:eax], bx&lt;br /&gt;
&lt;br /&gt;
   jmp $                  ; loop forever&lt;br /&gt;
&lt;br /&gt;
gdtinfo:&lt;br /&gt;
   dw gdt_end - gdt - 1   ;last byte in table&lt;br /&gt;
   dd gdt                 ;start of table&lt;br /&gt;
&lt;br /&gt;
gdt         dd 0,0        ; entry 0 is always unused&lt;br /&gt;
flatdesc    db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0&lt;br /&gt;
gdt_end:&lt;br /&gt;
&lt;br /&gt;
   times 510-($-$$) db 0  ; fill sector w/ 0's&lt;br /&gt;
   dw 0xAA55              ; Required by some BIOSes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* At least on the 486SL the jmp $+2 instruction is needed after toggling the PM bit off, not just on. - BASICFreak&lt;br /&gt;
&lt;br /&gt;
=== 巨非实模式(Huge Unreal Mode) ===&lt;br /&gt;
巨非实模式使代码超过64KiB。 然而，由于实模式中断不会自动保存EIP的高16位，因此实现起来更加困难。 初始化很简单，你只需加载一个4GiB限制的代码段:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
; 汇编示例&lt;br /&gt;
&lt;br /&gt;
; nasm boot.asm -o boot.bin&lt;br /&gt;
; partcopy boot.bin 0 200 -f0&lt;br /&gt;
&lt;br /&gt;
[ORG 0x7c00]              ; add to offsets&lt;br /&gt;
&lt;br /&gt;
start:   xor ax, ax       ; make it zero&lt;br /&gt;
&lt;br /&gt;
   ...                    ; As before&lt;br /&gt;
&lt;br /&gt;
   mov  cr0, eax&lt;br /&gt;
   jmp 0x8:pmode&lt;br /&gt;
pmode:&lt;br /&gt;
   mov  bx, 0x10          ; select descriptor 2, instead of 1&lt;br /&gt;
   mov  ds, bx            ; 10h = 10000b&lt;br /&gt;
&lt;br /&gt;
   and al,0xFE            ; back to realmode&lt;br /&gt;
   mov  cr0, eax          ; by toggling bit again&lt;br /&gt;
   jmp 0x0:huge_unreal&lt;br /&gt;
huge_unreal:&lt;br /&gt;
&lt;br /&gt;
   ...                    ;As before&lt;br /&gt;
&lt;br /&gt;
gdtinfo:&lt;br /&gt;
   dw gdt_end - gdt - 1   ;last byte in table&lt;br /&gt;
   dd gdt                 ;start of table&lt;br /&gt;
&lt;br /&gt;
gdt         dd 0,0        ; entry 0 is always unused&lt;br /&gt;
flatcode    db 0xff, 0xff, 0, 0, 0, 10011010b, 10001111b, 0&lt;br /&gt;
flatdata    db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0&lt;br /&gt;
gdt_end:&lt;br /&gt;
&lt;br /&gt;
   times 510-($-$$) db 0  ; fill sector w/ 0's&lt;br /&gt;
   dw 0xAA55              ; Required by some BIOSes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
警告：这可能在某些模拟器或某些硬件上不起作用。&lt;br /&gt;
&lt;br /&gt;
== 编译器支持 ==&lt;br /&gt;
===Smaller C===&lt;br /&gt;
[[Smaller C]]编译器支持非实模式。 它为虚实模式生成[[MZ]]可执行文件(可以用[[BootProg]]加载)。&lt;br /&gt;
&lt;br /&gt;
代码和堆栈将位于1MB标记以下，并且堆栈大小受64KB限制 （瞧，CS:(E)IP，SS:(E)SP，这是DOS中MZ可执行文件的自然设置）没有什么不寻常的。 DS和ES段寄存器设置为0，因此C指针可以作为平面32位物理地址和地址数据或内存映射设备在前4 GB内存中的任何位置工作。&lt;br /&gt;
&lt;br /&gt;
这些可执行文件的启动代码执行必要的重定位（只有自定义重定位，没有标准的MZ重定位，这可能会简化可执行文件的加载），并在将控制权传递给等价的“main()”之前设置非真实模式。 有关如何编写虚实模式的汇编代码位的信息，请参阅编译器源代码树中srclib下的“srclib/c0du.asm”和其他C/汇编代码(请查看#ifdef__unreal__‘下的(“内联汇编”)”)。&lt;br /&gt;
&lt;br /&gt;
你可以在DOS中尝试非实模式 (例如在DOSBox，VirtualBox FreeDOS中)，因为编译器完全支持其C库中的DOS非实模式组合。 ''tests/vesalfb.c''是一个简单的例子，可以在启用线性帧缓冲区的情况下设置[[VESA]]图形模式，并在屏幕上以非真实模式绘制一些东西。&lt;br /&gt;
&lt;br /&gt;
有关用Smaller C实现非实模式[[BootLoader]]的示例，请参阅[https://github.com/fysnet/FYSOS/tree/master/loader FYSOS]。&lt;br /&gt;
[[Category:X86 CPU]]&lt;br /&gt;
[[Category:FAQ]]&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>