- /*
- * The actual transition into protected mode
- * 文档:
- * /arch/x86/include/asm/segment.h 【1】
- * /arch/x86/boot/pmjump.S【本文】
- */
- #include <asm/boot.h>
- #include <asm/processor-flags.h>
- #include <asm/segment.h>
- #include <linux/linkage.h>
- .text
- .code16 /*16位汇编*/
- /*
- * void protected_mode_jump(u32 entrypoint, u32 bootparams);
- * 内核中调用都是fastcall的,所以两个参数对应为:
- * EAX:参数1=boot_params.hdr.code32_start@pm.c
- * EDX=(u32)&boot_params + (ds() << 4)@pm.c
- * 根据前文,EAX中的值是压缩内核入口(未hook的情况下),EDX的值是
- * boot_params的地址。pm.c中ds值是loader加载内核载地址X所在的
- * 段,在document/x86/boot.txt中对X有描述。其它段自header.S进入
- * boot/main.c后,也没变过都等于X。
- */
- GLOBAL(protected_mode_jump)
- movl %edx, %esi //esi指向boot_params
- xorl %ebx, %ebx //ebx清零
- movw %cs, %bx //bx存实模式代码段基址(等于X)
- /*
- * 将ebx左移4位再加上2f处的变量值再将结果存入2f所指的内存变量里。
- * 在这句命令之前,2f处原来的值是in_pm32的偏移值。这样做的意思是
- * 将cs:in_pm32计算出的线性(即in_pm32的物理)地址存入2f处的变量里。
- */
- shll $4, %ebx
- addl %ebx, 2f
- jmp 1f # Short jump to serialize on 386/486
- 1:
- movw $__BOOT_DS, %cx
- movw $__BOOT_TSS, %di
- movl %cr0, %edx
- orb $X86_CR0_PE, %dl # 这里开启cr0的保护模式位
- movl %edx, %cr0
- # Transition to 32-bit mode
- /*
- * 上面几句已经打开了保护模式,在临时的gdt中的代码段、数据段
- * 段基址被设置为0(在setup_gdt@pm.c中)。
- * 下面几句要通过保护模式的方法跳转到in_pm32处---用段选择子在gdt
- * 中选出cs所指的段,段基址加上偏移量(即2f处的内存值)进行跳转。上
- * 面说了,cs所指的gdt段段基址为0,所以实际跳转量也是2f处的值
- * (cs:in_pm32=in_pm32的物理地址值)。
- * 同时注意,实模式下用的是物理地址,而现在由于没开分页机制,所以计
- * 算出来的地址也是物理地址,这才保证了in_pm32能成功由下面指令跳
- * 过去---偏移是在实模式算出的,跳转是在开启了保护模式后进行的。
- */
- .byte 0x66, 0xea # ljmpl 指令
- 2: .long in_pm32 # offset
- .word __BOOT_CS # 段选择子
- ENDPROC(protected_mode_jump)
- /*
- * 到这个函数时寄存器:
- * eax=压缩内核线性地址(protected_mode_jump的参数)
- * cs=__BOOT_CS代码段选择子
- * cx=__BOOT_DS段选择子
- * di=__BOOT_TSS段选择子
- */
- .code32 /*32位的汇编*/
- .section ".text32","ax" /*段定义*/
- GLOBAL(in_pm32)
- # Set up data segments for flat 32-bit mode
- /*将ds,es,fs,gs,ss等段选择子都设置成__BOOT_DS*/
- 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.
- /*
- * bx存放实模式cs值(内核地址X所在段),ebx等于cs左移过4位
- * sp在header.S中被设置成了相对于X的段基址的偏移量,
- * 现在esp=ebx+esp=栈顶指针,其实esp的值现在是个32位线性
- * 地址,值与实模式下线性地址相同。
- */
- addl %ebx, %esp
- # Set up TR to make Intel VT happy
- /*设置任务状态段寄存器*/
- ltr %di
- # 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
- /*设置ldt的值,cx=0*/
- lldt %cx
- jmpl *%eax # Jump to the 32-bit entrypoint
- ENDPROC(in_pm32)
- /*
- * 到此为止,所有寄存器值:
- * edi=__BOOT_TSS
- * ecx,edx,ebx,ebp,edi=0
- * esi=boot_params
- * ds,es,fs,gs,ss=__BOOT_DS
- * cs=__BOOT_CS代码段选择子
- * eax=压缩内核入口
- * esp=合适的栈顶
- *
- * __BOOT_CS,__BOOT_DS,__BOOT_TSS的值分别指向临时gdt(pm.c)的第2,3,4项
- *
- */
转载于:https://www.cnblogs.com/cybertitan/archive/2012/10/10/2719018.html