linux-boot-arch_x86_boot_compressed_head_32

原文链接:http://www.cnblogs.com/cybertitan/archive/2012/10/10/2719020.html        /* 
  1.  *  linux/boot/head.S 
  2.  * 
  3.  *  Copyright (C) 1991, 1992, 1993  Linus Torvalds 
  4.  */  
  5.   
  6. /* 
  7.  *  head.S contains the 32-bit startup code. 
  8.  * 
  9.  * NOTE!!! Startup happens at absolute address 0x00001000, which is also where 
  10.  * the page directory will exist. The startup code will be overwritten by 
  11.  * the page directory. [According to comments etc elsewhere on a compressed 
  12.  * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] 
  13.  * 
  14.  * Page 0 is deliberately kept safe, since System Management Mode code in 
  15.  * laptops may need to access the BIOS data stored there.  This is also 
  16.  * useful for future device drivers that either access the BIOS via VM86 
  17.  * mode. 
  18.  */  
  19.   
  20. /* 
  21.  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 
  22.  * 这段代码负责解压内核,首先将内核移动到一个临时位置,然后再解压到加载 
  23.  * 地址,一般是1M。 
  24.  */  
  25.     .text  
  26.   
  27. #include <linux/init.h>  
  28. #include <linux/linkage.h>  
  29. #include <asm/segment.h>  
  30. #include <asm/page_types.h>  
  31. #include <asm/boot.h>  
  32. #include <asm/asm-offsets.h>  
  33.   
  34.     __HEAD  
  35. ENTRY(startup_32)  
  36. //EFI 启动相关  
  37. #ifdef CONFIG_EFI_STUB  
  38.     jmp preferred_addr  
  39.   
  40.     .balign 0x10  
  41.     /* 
  42.      * We don't need the return address, so set up the stack so 
  43.      * efi_main() can find its arugments. 
  44.      */  
  45.     add $0x4, %esp  
  46.   
  47.     call    efi_main  
  48.     cmpl    $0, %eax  
  49.     movl    %eax, %esi  
  50.     jne 2f  
  51. 1:  
  52.     /* EFI init failed, so hang. */  
  53.     hlt  
  54.     jmp 1b  
  55. 2:  
  56.     call    3f  
  57. 3:  
  58.     popl    %eax  
  59.     subl    $3b, %eax  
  60.     subl    BP_pref_address(%esi), %eax  
  61.     add BP_code32_start(%esi), %eax  
  62.     leal    preferred_addr(%eax), %eax  
  63.     jmp *%eax  
  64.   
  65. preferred_addr:  
  66. #endif  
  67.     cld  
  68.     /* 
  69.      * Test KEEP_SEGMENTS flag to see if the bootloader is asking 
  70.      * us to not reload segments 
  71.      * 在/Documentation/x86/boot.txt指出,BIT6是KEEP_SEGMENTS(段保持) 
  72.      * 在32位入口处需要判断此标志。 
  73.      * 0:重新设置各段寄存器为__BOOT_DS 
  74.      * 1:保持原来值 
  75.      */  
  76.     testb   $(1<<6), BP_loadflags(%esi)  
  77.     jnz 1f  
  78.   
  79.     cli  
  80.     movl    $__BOOT_DS, %eax  
  81.     movl    %eax, %ds  
  82.     movl    %eax, %es  
  83.     movl    %eax, %fs  
  84.     movl    %eax, %gs  
  85.     movl    %eax, %ss  
  86. 1:  
  87.   
  88. /* 
  89.  * Calculate the delta between where we were compiled to run 
  90.  * at and where we were actually loaded at.  This can only be done 
  91.  * with a short local call on x86.  Nothing  else will tell us what 
  92.  * address we are running at.  The reserved chunk of the real-mode 
  93.  * data at 0x1e4 (defined as a scratch field) are used as the stack 
  94.  * for this calculation. Only 4 bytes are needed. 
  95.  * call 的压栈动作会将1f的实际地址放入esp(即scratch字段)中。 
  96.  * call句会将下一条指令开始地址存入栈中,即 
  97.  * 相当于push 1f,jmp offset.而对于push栈而言,执行过程类似esp-=4, 
  98.  * mov 1f esp.就是说esp会先减4,然后再将值存入。这就是+4产生的原因。  
  99.  * 1f对本地call指令而言,被汇编成一个偏移量,即1f离本call语句的偏移,所以 
  100.  * call在运行时可准确地将其下一条指令的实际地址放入栈中。 
  101.  * 而subl句它引用的1:会被汇编成一个绝对地址(理论值)。 
  102.  * 所以popl后,ebp中存放的是标号1:的实际值,它减去理论值的差值再存入ebp 
  103.  * 中。 
  104.  */  
  105.     leal    (BP_scratch+4)(%esi), %esp  
  106.     call    1f  
  107. 1:  popl    %ebp  
  108.     subl    $1b, %ebp  
  109.   
  110. /* 
  111.  * %ebp contains the address we are loaded at by the boot loader and %ebx 
  112.  * contains the address where we should move the kernel image temporarily 
  113.  * for safe in-place decompression. 
  114.  * 既然上面ebp算出的是个delta,那么再加个offset有什么用? 
  115.  * 假设编译时内核映像是以0为基址的:那在popl句中,ebp是标号1的实际地址,而标 
  116.  * 号1:是它距内核映像基址的偏移量。标号1实际地址-它距内核映像基址偏移量= 
  117.  * 内核映像基址的实际地址=startup_32标号的实际地址。 
  118.  *  
  119.  * 在vmlinux.lds.S中是startup_32入口地址,并且假设其被加载到address 0,与上 
  120.  * 面假设符合。 
  121.  *  
  122.  * 下列代码是设置对齐 
  123.  */  
  124.   
  125. #ifdef CONFIG_RELOCATABLE  
  126.     movl    %ebp, %ebx  
  127.     movl    BP_kernel_alignment(%esi), %eax  
  128.     decl    %eax  
  129.     addl    %eax, %ebx  
  130.     notl    %eax  
  131.     andl    %eax, %ebx  
  132. #else  
  133.     movl    $LOAD_PHYSICAL_ADDR, %ebx  
  134. #endif  
  135.   
  136.     /*  
  137.      * Target address to relocate to for decompression  
  138.      * 在对齐后的地址上加一个偏移作为解压地址 
  139.      */  
  140.     addl    $z_extract_offset, %ebx  
  141.   
  142.     /* Set up the stack */  
  143.     leal    boot_stack_end(%ebx), %esp  
  144.   
  145.     /* Zero EFLAGS */  
  146.     pushl   $0  
  147.     popfl  
  148.   
  149. /* 
  150.  * Copy the compressed kernel to the end of our buffer 
  151.  * where decompression in place becomes safe. 
  152.  * ebp是startup_32加载地址,而ebx是临时放压缩代码的地方 
  153.  */  
  154.     pushl   %esi  
  155.     leal    (_bss-4)(%ebp), %esi  
  156.     leal    (_bss-4)(%ebx), %edi  
  157.     movl    $(_bss - startup_32), %ecx  
  158.     shrl    $2, %ecx  
  159.     std //设置标志位使esi,edi在循环中递减  
  160.     rep movsl//倒着复制,因std作用  
  161.     cld //清方向标志位  
  162.     popl    %esi  
  163.   
  164. /* 
  165.  * 上面代码是从startup_32开始到_bss都复制到ebx开始的地 
  166.  * 方了,那下面这两句就是跳到新的、以ebx为首址的relocated 
  167.  * 的位置。 
  168.  * Jump to the relocated address. 
  169.  */  
  170.     leal    relocated(%ebx), %eax  
  171.     jmp *%eax  
  172. ENDPROC(startup_32)  
  173.   
  174.     .text  
  175. relocated:  
  176.   
  177. /* 
  178.  * Clear BSS (stack is currently empty) 
  179.  * bss段清零 
  180.  */  
  181.     xorl    %eax, %eax  
  182.     leal    _bss(%ebx), %edi  
  183.     leal    _ebss(%ebx), %ecx  
  184.     subl    %edi, %ecx  
  185.     shrl    $2, %ecx  
  186.     rep stosl  
  187.   
  188. /* 
  189.  * Adjust our own GOT 
  190.  * global offset table全局变量表 
  191.  */  
  192.     leal    _got(%ebx), %edx  
  193.     leal    _egot(%ebx), %ecx  
  194. 1:  
  195.     cmpl    %ecx, %edx  
  196.     jae 2f  
  197.     addl    %ebx, (%edx)  
  198.     addl    $4, %edx  
  199.     jmp 1b  
  200. 2:  
  201.   
  202. /* 
  203.  * Do the decompression, and jump to the new kernel.. 
  204.  * 在上面ebx是ebp对齐后再加上z_extract_offset的值 
  205.  * 现在给ebx减去z_extract_offset就是ebp对齐的值 
  206.  * 即原加载地址(startup_32)对齐后的地址(放入ebp)。 
  207.  * decompress_kernel函数在/arch/x86/boot/compressed/misc.c 
  208.  * 中定义 
  209.  */  
  210.     leal    z_extract_offset_negative(%ebx), %ebp  
  211.                 /* push arguments for decompress_kernel: */  
  212.     pushl   %ebp        /* output address */  
  213.     pushl   $z_input_len    /* input_len 压缩内核大小*/  
  214.     leal    input_data(%ebx), %eax  
  215.     pushl   %eax        /* input_data压缩内核开始地址 */  
  216.     leal    boot_heap(%ebx), %eax  
  217.     pushl   %eax        /* heap area 工作堆*/  
  218.     pushl   %esi        /* real mode pointer 是boot_params*/  
  219.     call    decompress_kernel  
  220.     addl    $20, %esp   //恢复栈,5个参数  
  221.   
  222. #if CONFIG_RELOCATABLE  
  223. /* 
  224.  * Find the address of the relocations. 
  225.  */  
  226.     leal    z_output_len(%ebp), %edi  
  227.   
  228. /* 
  229.  * Calculate the delta between where vmlinux was compiled to run 
  230.  * and where it was actually loaded. 
  231.  */  
  232.     movl    %ebp, %ebx  
  233.     subl    $LOAD_PHYSICAL_ADDR, %ebx  
  234.     jz  2f  /* Nothing to be done if loaded at compiled addr. */  
  235. /* 
  236.  * Process relocations. 
  237.  */  
  238.   
  239. 1:  subl    $4, %edi  
  240.     movl    (%edi), %ecx  
  241.     testl   %ecx, %ecx  
  242.     jz  2f  
  243.     addl    %ebx, -__PAGE_OFFSET(%ebx, %ecx)  
  244.     jmp 1b  
  245. 2:  
  246. #endif  
  247.   
  248. /* 
  249.  * Jump to the decompressed kernel. 
  250.  * ebx清零,跳到加载地址,现在加载地址上是解压后的内核 
  251.  * 跳转地址还是ebp,是压缩内核被加载地址对齐后的地址 
  252.  */  
  253.     xorl    %ebx, %ebx  
  254.     jmp *%ebp  
  255.   
  256. /* 
  257.  * Stack and heap for uncompression 
  258.  */  
  259.     .bss  
  260.     .balign 4  
  261. boot_heap:  
  262.     .fill BOOT_HEAP_SIZE, 1, 0  
  263. boot_stack:  
  264.     .fill BOOT_STACK_SIZE, 1, 0  
  265. boot_stack_end:  
  266. /* 
  267.  * esi=boot_params(未变) 
  268.  * ebp=内核加载地址(1M?) 
  269.  * ebx=0 
  270.  * 段寄存器=24=$__BOOT_DS 
  271.  * 其它通用寄存器都有变化 
  272.  * 本文用到的一些标号可以在arch/x86/boot/compressed/mkpiggy.c中找到, 
  273.  * 它是编译过程中的辅助程序。 这个文件会产生piggy.S,它的主要目的就 
  274.  * 是导出一些符号,由mkpiggy.c中的printf实现。 
  275.  */  

转载于:https://www.cnblogs.com/cybertitan/archive/2012/10/10/2719020.html

上一篇:Aspack壳代码分析


下一篇:Linux中的汇编语言