http://blog.chinaunix.net/uid-1701789-id-147545.html
进入保护模式的代码相当短,在pmjump.S中。我们就来一点一点看到底是如何进入保护模式的。
- /*
- * The actual transition into protected mode
- */
- #include <asm/boot.h>
- #include <asm/processor-flags.h>
- #include <asm/segment.h>
- #include <linux/linkage.h>
- .text
- .code16
- /*
- * void protected_mode_jump(u32 entrypoint, u32 bootparams); 这里的entrypoint就是32位kernel启动代码的入口,通过code32_start传入,bootparams是已经整理好的32位的线性地址,不需要进一步转换转换。eax是entrypoint,edx是bootparams。
- */
- GLOBAL(protected_mode_jump)
- movl %edx, %esi # Pointer to boot_params table //保存boot_params的指针
- xorl %ebx, %ebx
- movw %cs, %bx
- shll $4, %ebx //ebx里面是实模式启动代码所用到的空间上限
- addl %ebx, 2f //2f位置的内容是指向in_pm32的相对位移,调整该位移以指向in_pm32在实际内存中的地址。
- jmp 1f # Short jump to serialize on 386/486
- 1:
//_BOOT_DS和_BOOT_TSS在arch/x86/include/asm/Segment.h里面定义。
- movw $__BOOT_DS, %cx
- movw $__BOOT_TSS, %di
- movl %cr0, %edx
- orb $X86_CR0_PE, %dl # Protected mode
- movl %edx, %cr0 //CR0的保护模式置位
- # Transition to 32-bit mode。//跳转到in_pm32,设置完CR0之后必须使用长跳转来使CPU进入保护模式。
- .byte 0x66, 0xea # ljmpl opcode
- 2: .long in_pm32 # offset
- .word __BOOT_CS # segment
- ENDPROC(protected_mode_jump)
- .code32
- .section ".text32","ax"
- GLOBAL(in_pm32)
- # Set up data segments for flat 32-bit mode
- //初始化数据段,ecx=_BOOT_DS,是在go_to_protected_mode里面设定的DS的选择字。是相对于GDT头的位移量。在arch/x86/include/asm/Segment.h里面定义。实际上这个选择字指向的是0-4G的所有内存空间,和CS是一样的。
- movl %ecx, %ds
- movl %ecx, %es
- movl %ecx, %fs
- movl %ecx, %gs
- movl %ecx, %ss
- # The 32-bit code sets up its own stack, but this way we do have
- # a valid stack if some debugging hack wants to use it.
- addl %ebx, %esp //初始化堆栈。将原先实模式启动代码的空间全部用作堆栈。
- # Set up TR to make Intel VT happy
- ltr %di //设置Task Stack Segment. %di里面是TSS的选择字。该选择字在GDT里,
- # Clear registers to allow for future extensions to the
- # 32-bit boot protocol
- xorl %ecx, %ecx
- xorl %edx, %edx
- xorl %ebx, %ebx
- xorl %ebp, %ebp
- xorl %edi, %edi
- # Set up LDTR to make Intel VT happy
- lldt %cx //将LDTR设为0
- jmpl *%eax # Jump to the 32-bit entrypoint //让我们跳到code32_start吧。
- ENDPROC(in_pm32)