至此linux首次进入保护模式所需的准备工作已经基本完成,段描述符表准备好了,而且GDTR也设置完毕了。

&nbsp; &nbsp;&nbsp;那么接下来看一下<span style="-ms-word-wrap: break-word;">go_to_protected_mode()</span>最后的调用:

protected_mode_jump(boot_params.hdr.code32_start, (u32)&boot_params + (ds() << 4));

&nbsp; &nbsp;&nbsp;这是由<span style="-ms-word-wrap: break-word;">C</span>语言跳转到汇编的一个调用,<span style="-ms-word-wrap: break-word;">protected_mode_jump</span>是纯汇编实现的一个函数:


1. 【file:/arch/x86/boot/pmjump.s】
2. /
3.   void protected_mode_jump(u32 entrypoint, u32 bootparams);
4.  /
5. GLOBAL(protected_mode_jump)
6.      movl %edx, %esi # Pointer to boot_params table
7.  
8.      xorl %ebx, %ebx
9.      movw %cs, %bx
10.      shll $4, %ebx
11.      addl %ebx, 2f
12.      jmp 1f # Short jump to serialize on 386/486
13. 1:
14.  
15.      movw $BOOT_DS, %cx
16.      movw $
BOOT_TSS, %di
17.  
18.      movl %cr0, %edx
19.      orb $X86_CR0_PE, %dl # Protected mode
20.      movl %edx, %cr0
21.  
22.      # Transition to 32-bit mode
23.      .byte 0x66, 0xea # ljmpl opcode
24. 2: .long in_pm32 # offset
25.      .word __BOOT_CS # segment
26. ENDPROC(protected_mode_jump)
27.  
28.      .code32
29.      .section ".text32","ax"
30. GLOBAL(in_pm32)
31.      # Set up data segments for flat 32-bit mode
32.      movl %ecx, %ds
33.      movl %ecx, %es
34.      movl %ecx, %fs
35.      movl %ecx, %gs
36.      movl %ecx, %ss
37.      # The 32-bit code sets up its own stack, but this way we do have
38.      # a valid stack if some debugging hack wants to use it.
39.      addl %ebx, %esp
40.  
41.      # Set up TR to make Intel VT happy
42.      ltr %di
43.  
44.      # Clear registers to allow for future extensions to the
45.      # 32-bit boot protocol
46.      xorl %ecx, %ecx
47.      xorl %edx, %edx
48.      xorl %ebx, %ebx
49.      xorl %ebp, %ebp
50.      xorl %edi, %edi
51.  
52.      # Set up LDTR to make Intel VT happy
53.      lldt %cx
54.  
55.      jmpl %eax # Jump to the 32-bit entrypoint
56. ENDPROC(in_pm32)
&nbsp; &nbsp;&nbsp;其实<span style="-ms-word-wrap: break-word;">C</span>语言调用跳转汇编函数没什么特殊的,就<span style="-ms-word-wrap: break-word;">call</span>指令就完了。真正要理解这段汇编的实现,侧重要了解参数的传递方式。

&nbsp; &nbsp;&nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">我们通常都知悉</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">Intel</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">通常都是通过压栈传参的,以至于</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">gdb</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">调试程序时,可以通过</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">bt</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">查看到各个函数调用时的传参信息。如果要是有接触过</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">ARM</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">、</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MIPS</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">、</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">PPC</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">处理器底层的程序开发的话,大体都知道它们的参数是通过寄存器传递的。比如</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">ARM</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">处理器,</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">C</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">语言函数调用时,通常将</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">R0-R3</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">等</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">4</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">个寄存器存储参数</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">0</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">到</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">4</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">的值传递到子函数中,如果参数超过</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">4</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">个则多余的参数将会压栈传递,而</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">R0</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">还会用来作为子函数返回值传递回去。而在内核中</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">/arch/boot</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">下面的代码也采用了类似的寄存器传递参数的方式,三个及以内的参数分别依序以</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">eax</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">、</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">edx</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">、</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">ecx</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">作为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">0</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">到</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">3</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">的入参,如果超过</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">3</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">个,这会采用压栈传参。</span>

&nbsp; &nbsp;&nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">既然已经知悉传参方式了,那么接下来看一下代码实现:</span>

movl                             %edx, %esi

&nbsp; &nbsp;&nbsp;这里是把入参<span style="-ms-word-wrap: break-word;">boot_params</span>的地址保存到<span style="-ms-word-wrap: break-word;">esi</span>中,而自此<span style="-ms-word-wrap: break-word;">esi</span>就不再在此<span style="-ms-word-wrap: break-word;">pmjump.s</span>的汇编代码中出现,所以可以推测这个是用来以备后用的,它不是这里的关键数据。

&nbsp; &nbsp;&nbsp;紧接着:

xorl                             %ebx, %ebx

movw&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %cs, %bx


shll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $4, %ebx


addl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %ebx, 2f
&nbsp; &nbsp;&nbsp;将<span style="-ms-word-wrap: break-word;">ebx</span>清空后,把&ldquo;<span style="-ms-word-wrap: break-word;">2: .long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in_pm32</span>&rdquo;的物理地址保存到<span style="-ms-word-wrap: break-word;">ebx</span>上。待会儿再讲一下它的作用。

&nbsp; &nbsp;&nbsp;接着往下看:

movw                             $__BOOT_DS, %cx

movw&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $__BOOT_TSS, %di
&nbsp; &nbsp;&nbsp;我们找一下<span style="-ms-word-wrap: break-word;">__BOOT_DS</span>和<span style="-ms-word-wrap: break-word;">__BOOT_TSS</span>的定义:

&nbsp;


1. 【file:/arch/x86/include/asm/segment.h】
2. #define GDT_ENTRY_BOOT_CS 2
3. #define BOOT_CS (GDT_ENTRY_BOOT_CS * 8)
4.  
5. #define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1)
6. #define
BOOT_DS (GDT_ENTRY_BOOT_DS 8)
7.  
8. #define GDT_ENTRY_BOOT_TSS (GDT_ENTRY_BOOT_CS + 2)
9. #define __BOOT_TSS (GDT_ENTRY_BOOT_TSS 8)
<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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">&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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">GDT_ENTRY_BOOT_DS</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">,而</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">8</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">则是</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">2^3</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">,这里不是什么大小乘法,而是起到位移的作用,左移</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">3</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">位。因为段寄存器低端有</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">3bit</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">是预留给了</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">TI</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">和</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">RPL</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">的。然后把段值存到</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">cx</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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">寄存器中,这个后面会用到的。</span>

&nbsp;

好了,到关键代码了:

movl                             %cr0, %edx

orb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $X86_CR0_PE, %dl&nbsp;&nbsp; # Protected mode


movl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %edx, %cr0
&nbsp; &nbsp;&nbsp;可以看到将<span style="-ms-word-wrap: break-word;">cr0</span>的值暂存到<span style="-ms-word-wrap: break-word;">edx</span>中,然后将<span style="-ms-word-wrap: break-word;">edx</span>对应<span style="-ms-word-wrap: break-word;">cr0</span>的<span style="-ms-word-wrap: break-word;">PE</span>位进行设置,最后把<span style="-ms-word-wrap: break-word;">edx</span>设置到<span style="-ms-word-wrap: break-word;">cr0</span>上,至此,随着<span style="-ms-word-wrap: break-word;">cr0</span>的<span style="-ms-word-wrap: break-word;">PE</span>被置位将保护模式开启。开启后就到了:

                                 .byte  0x66, 0xea      # ljmpl opcode

2:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .long&nbsp; in_pm32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # offset


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .word&nbsp; __BOOT_CS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # segment
&nbsp; &nbsp;&nbsp;指令其本质就是数据,这些数据就构造成了一个长跳转指令,跳转的目的地址是&ldquo;<span style="-ms-word-wrap: break-word;">__BOOT_CS</span>:<span style="-ms-word-wrap: break-word;">in_pm32</span>&rdquo;(<span style="-ms-word-wrap: break-word;">segment</span>:<span style="-ms-word-wrap: break-word;">offset</span>),也就是将会跳转到<span style="-ms-word-wrap: break-word;">GLOBAL(in_pm32)</span>去执行下面的汇编指令<span style="-ms-word-wrap: break-word;">:</span>

movl                             %ecx, %ds

movl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %ecx, %es


movl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %ecx, %fs


movl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %ecx, %gs


movl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %ecx, %ss
&nbsp; &nbsp;&nbsp;好了,这里就看到刚才<span style="-ms-word-wrap: break-word;">cx</span>寄存器保存的值的作用了。它是用来设置各个段寄存器的,貌似少了<span style="-ms-word-wrap: break-word;">cs</span>寄存器的设置?非也,<span style="-ms-word-wrap: break-word;">cs</span>寄存器随着刚才的那个长跳转已经设置上去了,所以就没有必要做重复工作。

&nbsp; &nbsp;&nbsp;接下来顺带提一下<span style="-ms-word-wrap: break-word;">ebx</span>的用途:

addl                             %ebx, %esp

&nbsp; &nbsp;&nbsp;它是用来把地址设置给<span style="-ms-word-wrap: break-word;">esp</span>,栈寄存器。不过为什么指向代码段呢?根据注释可以了解之所以需要设置栈位置,是为了调试用的。但是至于指向代码段,这是由于这段代码只会执行一次,所以没有存在的意义,就当做废物利用吧,应该是这个意图。

&nbsp; &nbsp;&nbsp;完了,后面的汇编就不再详述了,至此已经进入保护模式了。整个过程看起来有点绕,实际上这是跟随<span style="-ms-word-wrap: break-word;">Intel</span>的手册说明来实现的,看一下手册关于进入保护模式的描述:


1. Switching to Protected Mode
2. Before switching to protected mode from real mode, a minimum set of system data structures and code modules must be loaded into memory, as described in Section 9.8, “Software Initialization for Protected-Mode Operation.” Once these tables are created, software initialization code can switch into protected mode.
3. Protected mode is entered by executing a MOV CR0 instruction that sets the PE flag in the CR0 register. (In the same instruction, the PG flag in register CR0 can be set to enable paging.)Execution in protected mode begins with a CPL of 0.
4. Intel 64 and IA-32 processors have slightly different requirements for switching to protected mode. To insure upwards and downwards code compatibility with Intel 64 and IA-32 processors, we recommend that you follow these steps:
5. 1. Disable interrupts. A CLI instruction disables maskable hardware interrupts. NMI interrupts can be disabled with external circuitry. (Software must guarantee that no exceptions or interrupts are generated during the mode switching operation.)
6. 2. Execute the LGDT instruction to load the GDTR register with the base address of the GDT.
7. 3. Execute a MOV CR0 instruction that sets the PE flag (and optionally the PG flag) in control register CR0.
8. 4. Immediately following the MOV CR0 instruction, execute a far JMP or far CALL instruction. (This operation is typically a far jump or call to the next instruction in the instruction stream.)
9. 5. The JMP or CALL instruction immediately after the MOV CR0 instruction changes the flow of execution and serializes the processor.
10. 6. If paging is enabled, the code for the MOV CR0 instruction and the JMP or CALL instruction must come from a page that is identity mapped (that is, the linear address before the jumpis the same as the physical address after paging and protected mode is enabled). The target instruction for the JMP or CALL instruction does not need to be identity mapped.
11. 7. If a local descriptor table is going to be used, execute the LLDT instruction to load the segment selector for the LDT in the LDTR register.
12. 8. Execute the LTR instruction to load the task register with a segment selector to the initial protected-mode task or to a writable area of memory that can be used to store TSS information on a task switch.
13. 9. After entering protected mode, the segment registers continue to hold the contents they had in real-address mode. The JMP or CALL instruction in step 4 resets the CS register. Perform one of the following operations to update the contents of the remaining segment registers.
14. — Reload segment registers DS, SS, ES, FS, and GS. If the ES, FS, and/or GS registers are not going to be used, load them with a null selector.
15. — Perform a JMP or CALL instruction to a new task, which automatically resets the values of the segment registers and branches to a new code segment.
16. 10. Execute the LIDT instruction to load the IDTR register with the address and limit of the protected-mode IDT.
17. 11. Execute the STI instruction to enable maskable hardware interrupts and perform the necessary hardware operation to enable NMI interrupts.
18. Random failures can occur if other instructions exist between steps 3 and 4 above. Failures will be readily seen in some situations, such as when instructions that reference memory are inserted between steps 3 and 4 while in system management mode.
<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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">&nbsp; &nbsp;&nbsp;可以看出来这个实现也不算是太复杂,是跟随着</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; line-height: 1.5; 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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">intel</span><span style="text-align: left; color: rgb(102, 102, 102); text-transform: none; line-height: 1.5; 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); -webkit-text-stroke-width: 0px; font-variant-ligatures: normal; font-variant-caps: normal;">的手册指引来实现的。</span>

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