既然都说是分析x86环境的linux系统内存管理,如果不分析一下x86那绕来绕去的内存映射机制,个人感觉等于什么都没分析。其实x86的内存映射机制,说复杂也不复杂,说简单也不简单,简单点说x86内存映射莫过于就两个映射:段式映射和页式映射。其中页式映射是基于段式映射的基础上而形成的,那就意味着可以是:纯段式映射和段页式映射。这些都是简单的,而且映射的结构图在各式各样介绍内存管理的书或者文章上比比皆是。但看点复杂的,GDTR存放的是虚拟地址还是线性地址呢?CR3存放的是线性地址还是物理地址?x86的各式寄存器分别在内存映射中起到了什么作用呢?这些都是值得探究的,如此一来可以更深入详细地理解x86体系结构。

&nbsp; &nbsp;&nbsp;直接把<span style="-ms-word-wrap: break-word;">x86</span>那几张内存映射机制结构图放上来没什么意思,还是循序渐进地结合<span style="-ms-word-wrap: break-word;">linux</span>内存初始化过程中的映射方式切换来分析这些映射吧。

&nbsp; &nbsp;&nbsp;机器通电启动的时候,<span style="-ms-word-wrap: break-word;">CPU</span>是处于实模式下的,这是很古老的模式,<span style="-ms-word-wrap: break-word;">intel 8086</span>就开始采用这种内存访问模式。不过那时候内存小,内存逐渐增大以及系统越来越负责,需要一个很好的内存保护方式,于是乎才有后来的保护模式。

&nbsp; &nbsp;&nbsp;那么实模式是如何地址翻译的呢?通过截取来自<span style="-ms-word-wrap: break-word;">intel</span>手册的实模式图来分析一下:

&nbsp;

&nbsp; &nbsp;&nbsp;翻译公式:

&nbsp; &nbsp;&nbsp;(<span style="line-height: 1.5; -ms-word-wrap: break-word;">Base</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">&lt;&lt;4)+</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">Offse</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">t</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp;= Linear Address</span>

&nbsp; &nbsp;&nbsp;由此我们可以看出来要访问某个物理地址,需要两个数据<span style="-ms-word-wrap: break-word;">offset</span>和<span style="-ms-word-wrap: break-word;">base</span>,其中<span style="-ms-word-wrap: break-word;">base</span>的数据就是实模式下段寄存器的值了(实模式下,段寄存器并不会当做描述符下标来使用),而<span style="-ms-word-wrap: break-word;">offset</span>则是需要访问的地址偏移。通过<span style="-ms-word-wrap: break-word;">base</span>左移<span style="-ms-word-wrap: break-word;">4</span>位加上<span style="-ms-word-wrap: break-word;">offset</span>的值则成为线性地址了,实模式下的线性地址直接映射物理地址,不做其他映射转换了。于是乎,实模式下表示逻辑地址的方式为&ldquo;<span style="-ms-word-wrap: break-word;">base</span>:<span style="-ms-word-wrap: break-word;">offset</span>&rdquo;。另外可以很明显地看到<span style="-ms-word-wrap: break-word;">base</span>和<span style="-ms-word-wrap: break-word;">offset</span>都为<span style="-ms-word-wrap: break-word;">0xffff</span>的时候,可以访问最大的地址值为<span style="-ms-word-wrap: break-word;">0x10FFEF </span>,而实际上的实模式是仅能够访问到<span style="-ms-word-wrap: break-word;">1M</span>的内存空间而已,至于从<span style="-ms-word-wrap: break-word;">0x100000</span>到<span style="-ms-word-wrap: break-word;">0x10ffef</span>的内存空间实际上是<span style="-ms-word-wrap: break-word;">0x0</span>到<span style="-ms-word-wrap: break-word;">0xffef</span>,通过&ldquo;<span style="-ms-word-wrap: break-word;">wrapping</span>&rdquo;迂回回去了。也就是意味着你操作<span style="-ms-word-wrap: break-word;">0x100000</span>到<span style="-ms-word-wrap: break-word;">0x10ffef</span>的内存实际上是在操作<span style="-ms-word-wrap: break-word;">0x0</span>到<span style="-ms-word-wrap: break-word;">0xffef</span>低地址的内存。情况如下图:

&nbsp;

 

&nbsp; &nbsp;&nbsp;这就是<span style="-ms-word-wrap: break-word;">Intel 8086</span>处理器所表现出来的内存访问方式了,也就是后来所谓的实模式了。<span style="-ms-word-wrap: break-word;">Intel</span>号称向下兼容,于是乎这种实模式的内存访问方式就完全被保留到了现在。

&nbsp; &nbsp;&nbsp;但是现在的计算机内存不可能仅有<span style="-ms-word-wrap: break-word;">1M</span>大小,截止目前,最新的电脑都基本上配备了<span style="-ms-word-wrap: break-word;">2G</span>及以上的内存了。而根据实模式的情况,是不可能访问超过<span style="-ms-word-wrap: break-word;">1M</span>以上的内存空间的,而现在面临着需要使用大内存的场景需要解决。即便不是现在,在<span style="-ms-word-wrap: break-word;">Intel 80286</span>的时候,已经不再是<span style="-ms-word-wrap: break-word;">20</span>根地址线了,而是升级为<span style="-ms-word-wrap: break-word;">24</span>根地址线了,访问内存达<span style="-ms-word-wrap: break-word;">16M</span>。所以这里面就有一个开关进行控制,这就是<span style="-ms-word-wrap: break-word;">A20 Gate</span>。这是指处理器上的<span style="-ms-word-wrap: break-word;">A20</span>线(即第<span style="-ms-word-wrap: break-word;">21</span>条地址线,地址线从<span style="-ms-word-wrap: break-word;">0</span>开始编号的),也是在<span style="-ms-word-wrap: break-word;">80286</span>设计时引入的。当<span style="-ms-word-wrap: break-word;">A20 Gate</span>开启时,则访问<span style="-ms-word-wrap: break-word;">0x100000</span>到<span style="-ms-word-wrap: break-word;">0x10ffef</span>的内存空间时是真正切切地访问了这块内存区域;当<span style="-ms-word-wrap: break-word;">A20 Gate</span>关闭时,则是仿<span style="-ms-word-wrap: break-word;">8086</span>的内存访问模式,访问的是<span style="-ms-word-wrap: break-word;">0x0</span>到<span style="-ms-word-wrap: break-word;">0xffef</span>的内存区域。

&nbsp; &nbsp;&nbsp;那我们看看<span style="-ms-word-wrap: break-word;">linux</span>内核开启<span style="-ms-word-wrap: break-word;">A20</span>的代码实现,实现开启功能的函数是<span style="-ms-word-wrap: break-word;">enable_a20</span>,具体代码:


1. 【file:/arch/x86/boot/a20.c】
2. /
3.   Actual routine to enable A20; return 0 on ok, -1 on failure
4.  /
5.  
6. #define A20_ENABLE_LOOPS 255 / Number of times to try /
7.  
8. int enable_a20(void)
9. {
10.        int loops = A20_ENABLE_LOOPS;
11.        int kbc_err;
12.  
13.        while (loops--) {
14.            / First, check to see if A20 is already enabled
15.           (legacy free, etc.) /
16.            if (a20_test_short())
17.                return 0;
18.           
19.            / Next, try the BIOS (INT 0x15, AX=0x2401) /
20.            enable_a20_bios();
21.            if (a20_test_short())
22.                return 0;
23.           
24.            / Try enabling A20 through the keyboard controller /
25.            kbc_err = empty_8042();
26.  
27.            if (a20_test_short())
28.                return 0; / BIOS worked, but with delayed reaction /
29.    
30.            if (!kbc_err) {
31.                enable_a20_kbc();
32.                if (a20_test_long())
33.                    return 0;
34.            }
35.           
36.            / Finally, try enabling the "fast A20 gate" */
37.            enable_a20_fast();
38.            if (a20_test_long())
39.                return 0;
40.        }
41.       
42.        return -1;
43. }
&nbsp; &nbsp;&nbsp;实现一目了然,就一个<span style="-ms-word-wrap: break-word;">while</span>循环调用函数,循环调用里面的各个函数。如果开启<span style="-ms-word-wrap: break-word;">A20</span>成功了,则在循环体内返回<span style="-ms-word-wrap: break-word;">0</span>表示成功,否则直至循环结束返回<span style="-ms-word-wrap: break-word;">-1</span>并退出以表示失败。

&nbsp; &nbsp;&nbsp;接下来看看<span style="-ms-word-wrap: break-word;">while</span>循环体内的函数。首先是<span style="-ms-word-wrap: break-word;">a20_test_short()</span>,顾名思义,可以看出来它是用来检测的,继而从<span style="-ms-word-wrap: break-word;">while</span>循环内的第一个判断可以推断出它是检测<span style="-ms-word-wrap: break-word;">A20</span>是否开启的,如果开启的话,则直接返回<span style="-ms-word-wrap: break-word;">0</span>表示成功。

&nbsp; &nbsp;&nbsp;具体函数内的实现:


1. 【file:/arch/x86/boot/a20.c】
2. static int a20_test_short(void)
3. {
4.     return a20_test(A20_TEST_SHORT);
5. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 而a20_test()的实现:</span>


1. 【file:/arch/x86/boot/a20.c】
2. #define A20_TEST_ADDR (40x80)
3. #define A20_TEST_SHORT 32
4. #define A20_TEST_LONG 2097152 / 2^21 /
5.  
6. static int a20_test(int loops)
7. {
8.     int ok = 0;
9.     int saved, ctr;
10.  
11.     set_fs(0x0000);
12.     set_gs(0xffff);
13.  
14.     saved = ctr = rdfs32(A20_TEST_ADDR);
15.  
16.     while (loops--) {
17.         wrfs32(++ctr, A20_TEST_ADDR);
18.         io_delay(); / Serialize and make delay constant */
19.         ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
20.         if (ok)
21.             break;
22.     }
23.  
24.     wrfs32(saved, A20_TEST_ADDR);
25.     return ok;
26. }
&nbsp; &nbsp;&nbsp;在<span style="-ms-word-wrap: break-word;">a20_test</span>里面,我们可以看到<span style="-ms-word-wrap: break-word;">set_fs(0x0000)</span>和<span style="-ms-word-wrap: break-word;">set_gs(0xffff)</span>分别将<span style="-ms-word-wrap: break-word;">fs</span>和<span style="-ms-word-wrap: break-word;">gs</span>设置为<span style="-ms-word-wrap: break-word;">0x0000</span>和<span style="-ms-word-wrap: break-word;">0xffff</span>。接着<span style="-ms-word-wrap: break-word;">rdfs32(A20_TEST_ADDR)</span>则是把<span style="-ms-word-wrap: break-word;">0x0000</span>:<span style="-ms-word-wrap: break-word;">(4*0x80)</span>地址的数据读取出来,至于是什么,天知道,不过这不是重点。再接着<span style="-ms-word-wrap: break-word;">while</span>循环体内,<span style="-ms-word-wrap: break-word;">wrfs32(++ctr, A20_TEST_ADDR)</span>把读出来的数据自加后写回到<span style="-ms-word-wrap: break-word;">0x0000</span>:<span style="-ms-word-wrap: break-word;">(4*0x80)</span>。然后<span style="-ms-word-wrap: break-word;">rdgs32(A20_TEST_ADDR+0x10) ^ ctr</span>则是把<span style="-ms-word-wrap: break-word;">0xffff</span>:<span style="-ms-word-wrap: break-word;">(4*0x80)+0x10</span>的数据读出来与写入<span style="-ms-word-wrap: break-word;">0x0000</span>:<span style="-ms-word-wrap: break-word;">(4*0x80)</span>的数据做异或运算,再在<span style="-ms-word-wrap: break-word;">if(ok)</span>里面判断两者是否相等。如果相等,则表明两者数据一致,有可能<span style="-ms-word-wrap: break-word;">wrfs32</span>写入的数据就是<span style="-ms-word-wrap: break-word;">rdgs32</span>读出来的数据,也就有可能当前<span style="-ms-word-wrap: break-word;">A20</span>并没有开启。如果存在巧合呢?这就是<span style="-ms-word-wrap: break-word;">while</span>循环的由来,多试几次避免真的是巧合。最后<span style="-ms-word-wrap: break-word;">wrfs32(saved, A20_TEST_ADDR)</span>再把修改的数据改回去。毕竟不知道这个数据有什么用,怎么来的就怎么回。

&nbsp; &nbsp;&nbsp;回到<span style="-ms-word-wrap: break-word;">enable_a20</span>函数里面,根据注释和操作可以判断,开启<span style="-ms-word-wrap: break-word;">A20 Gate</span>的函数分别有:<span style="-ms-word-wrap: break-word;">enable_a20_bios()</span>、<span style="-ms-word-wrap: break-word;">empty_8042()</span>、<span style="-ms-word-wrap: break-word;">enable_a20_kbc()</span>和<span style="-ms-word-wrap: break-word;">enable_a20_fast()</span>,而且<span style="-ms-word-wrap: break-word;">enable_a20_kbc()</span>更是直接调用<span style="-ms-word-wrap: break-word;">empty_8042()</span>,由此判断开启<span style="-ms-word-wrap: break-word;">A20</span>的关键函数只有<span style="-ms-word-wrap: break-word;">3</span>个。此外也不难理解,同理<span style="-ms-word-wrap: break-word;">e820</span>内存探测一样,这<span style="-ms-word-wrap: break-word;">3</span>个函数应该是向前或者是对各种硬件设计做兼容而实现的。

&nbsp; &nbsp;&nbsp;首先看一下<span style="-ms-word-wrap: break-word;">enable_a20_bios()</span>的实现:


1. 【file:/arch/x86/boot/a20.c】
2. static void enable_a20_bios(void)
3. {
4.     struct biosregs ireg;
5.  
6.     initregs(&ireg);
7.     ireg.ax = 0x2401;
8.     intcall(0x15, &ireg, NULL);
9. }
<span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">&nbsp; &nbsp;&nbsp;和</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">e820</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">内存探测很像的一个代码,这是通过调用</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">BIOS</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">的</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">0x15</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">中断尝试把</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">A20</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">开启。开启失败的话,将会调用</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">empty_8042(),</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">这是通过操作键盘控制器的状态寄存器尝试把</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">A20</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">开启,顺便提一下早期</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">IBM</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">为了解决</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">80286</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">兼容</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">8086</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">的内存访问模式,他们利用键盘控制其上空余的一些输出线来管理</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">A20</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">,这里应该就是针对这个情况尝试该方式开启</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">A20</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">,具体代码这里就不贴出来分析了。然后</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">empty_8042()</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">如果还失败的话,那么还有</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; -ms-word-wrap: break-word; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">enable_a20_fast()</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: 宋体, Arial; font-size: 16px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;">,这个是通过操作主板控制寄存器来尝试开启,背后故事就略了,这里不是重点。</span>

&nbsp; &nbsp;&nbsp;最后顺便记录一下<span style="-ms-word-wrap: break-word;">detect_memory()</span>在<span style="-ms-word-wrap: break-word;">Linux</span>系统中调用路径为:

main()                               #/arch/x86/boot/main.c

+&mdash;&mdash;<span style="-ms-word-wrap: break-word;">&gt; go_to_protected_mode()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #/arch/x86/boot/pm.c</span>


+&mdash;&mdash;<span style="-ms-word-wrap: break-word;">&gt;</span><span style="-ms-word-wrap: break-word;"> </span>enable_a20()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #/arch/x86/boot/a20.c
&nbsp; &nbsp;&nbsp;好了,截止现在打开<span style="-ms-word-wrap: break-word;">A20 Gate</span>,只是在实模式上使得处理器能够最大化访问<span style="-ms-word-wrap: break-word;">0x10ffef</span>的地址空间,而不是<span style="-ms-word-wrap: break-word;">wrap</span>回去访问低地址空间。但是要想访问<span style="-ms-word-wrap: break-word;">0x10ffef</span>以上的内存,则必须进入保护模式。

[http://blog.chinaunix.net/uid-26859697-id-4408665.html](http://blog.chinaunix.net/uid-26859697-id-4408665.html)