1、bzImage的生成过程

Android x86启动参数 安卓x86引导_system

上图是内核镜像bzimage的构建过程,包括如下过程:

1、构建内核镜像vmlinux,根据在内核配置阶段生成的.config将系统核心和built-in的系统组件进行编译,最后根据指定的链接脚本arch/i386/kernel/vmLinux.lds生成vmLinux文件。

2、对vmlinux进行瘦身并进行压缩,通过gzip对vmlinux.bin进行压缩。

3、构建包含解压缩代码的vminux镜像,使用连接器ld将包含压缩的系统核心的文件piggy.o与head.o,misc.o链接生成新的文件boot/compressed/vmLinux.

4、对新生成的vmlinux再次瘦身。

5、构建内核镜像bzImage,利用内核镜像构建工具build将bootsect,setup,vmLinux.bin三个文件依次放到bzImage文件中去。bootsect是一个引导扇区,一般情况下是512字节,最后两个字节为55AA.然后填充setup部分,补足512字节。

2、内核引导过程中涉及的文件


(1)arch/i386/boot/bootsect.S

(2)arch/i386/boot/setup.S

(3)arch/i386/boot/compressed/head.S


(4)arch/i386/boot/compressed/misc.c

(5)arch/i386/kernel/head.S

(6)init/main.c

3、第一个文件(1)arch/i386/boot/bootsect.S,在另一篇i386的引导协议中说过,这一部分,不再具有引导能力,主要就是传递一些参数。所以只看一小部分源码,如下:

SETUPSECTS= 4/* default nr of setup-sectors */
 BOOTSEG = 0x07C0/* original address of boot-sector */
 INITSEG = DEF_INITSEG/* we move boot here - out of the way */
 SETUPSEG = DEF_SETUPSEG/* setup starts here */
 SYSSEG = DEF_SYSSEG/* system loaded at 0x10000 (65536) */
 SYSSIZE = DEF_SYSSIZE/* system size: # of 16-byte clicks */
/* to be loaded */
 ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
 SWAP_DEV = 0  /* SWAP_DEV is now written by "build" */
setup_sects:.byte SETUPSECTS
 root_flags: .word ROOT_RDONLY
 syssize: .word SYSSIZE
 swap_dev: .word SWAP_DEV
 ram_size: .word RAMDISK
 vid_mode: .word SVGA_MODE
 root_dev: .word ROOT_DEV


boot_flag: .word 0xAA55必须以此结尾

4、第二个文件(2)arch/i386/boot/setup.S,主要是探测系统的资源。在引导程序如GRUB装载完内核后,系统的控制全就交给此文件。此文件的主要工作是通过BIOS获得系统的配置信息,并将信息存到对应的内存位置,等待系统初始化时使用。

所做工作如下:

(1)、探测系统配置信息,并将探测的信息存到相应的内存单元中,

(2)、设置系统的全局描述表和中断描述符表。

(3)、进入保护模式

(4)、跳转到__BOOT_DS:0x100000,该地址对应于物理地址0x100000。此处正是经过压缩的内核的位置。

源码就不列出了,但列出下面这段本文件开头的注释,这段注释已经把此文件要做的工作,详细说明了。

/*
  * setup.S  Copyright (C) 1991, 1992 Linus Torvalds
  *
 * setup.s is responsible for getting the system data from the BIOS,
  * and putting them into the appropriate places in system memory.
  * both setup.s and system has been loaded by the bootblock.
  *
  * This code asks the bios for memory/disk/other parameters, and
  * puts them in a "safe" place: 0x90000-0x901FF, ie where the
  * boot-block used to be. It is then up to the protected mode
  * system to read them from there before the area is overwritten
  * for buffer-blocks.
  *
  * Move PS/2 aux init code to psaux.c
  * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
  *
  * some changes and additional features by Christoph Niemann,
  * March 1993/June 1994 (Christoph.Niemann@linux.org)
  *
  * add APM BIOS checking by Stephen Rothwell, May 1994
  * (sfr@canb.auug.o
  rg.au)
  *
  * High load stuff, initrd support and position independency
  * by Hans Lermen & Werner Almesberger, February 1996
  * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
  *
  * Video handling moved to video.S by Martin Mares, March 1996
  * <mj@k332.feld.cvut.cz>*
  * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
  * parsons) to avoid loadlin confusion, July 1997
  *
  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  * <stiker@northlink.com>
  *
  * Fix to work around buggy BIOSes which dont use carry bit correctly
  * and/or report extended memory in CX/DX for e801h memory size detection 
  * call.  As a result the kernel got wrong figures.  The int15/e801h docs
  * from Ralf Brown interrupt list seem to indicate AX/BX should be used
  * anyway.  So to avoid breaking many machines (presumably there was a reason
  * to orginally use CX/DX instead of AX/BX), we do a kludge to see
  * if CX/DX have been changed in the e801 call and if so use AX/BX .

5、此两个文件主要是压缩内核镜像的解压缩。这两个文件调用gnuzip解压缩内核piggy.o解压缩并释放到逻辑地址__BOOT_DS:_PHYSICAL_START处,并跳转到该地址开始系统的初始化过程。

(3)arch/i386/boot/compressed/head.S


(4)arch/i386/boot/compressed/misc.c

6、(5)arch/i386/kernel/head.S本文件为系统建立一个初步的页表,启用分页机制;装载了新的GDT、IDT,设置栈指针寄存器指向0号进程init_task内核态的栈底。最后跳到位于文件/init/main.c的系统初始化函数start_kernel,继续进行系统的初始化工作。列出其中一段源码:

/*
  * Initialize page tables.  This creates a PDE and a set of page
  * tables, which are located immediately beyond _end.  The variable
  * init_pg_tables_end is set up to point to the first "safe" location.
  * Mappings are created both at virtual address 0 (identity mapping)
  * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END.
  *
  * Warning: don't use %esi or the stack in this code.  However, %esp
  * can be used as a GPR if you really need it...
  */
 page_pde_offset = (__PAGE_OFFSET >> 20);


movl $(pg0 - __PAGE_OFFSET), %edi
movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
movl $0x007, %eax/* 0x007 = PRESENT+RW+USER */
 10:
leal 0x007(%edi),%ecx/* Create PDE entry */
movl %ecx,(%edx)/* Store identity PDE entry */
movl %ecx,page_pde_offset(%edx)/* Store kernel PDE entry */
addl $4,%edx
movl $1024, %ecx
 11:
stosl
addl $0x1000,%eax
loop 11b
/* End condition: we must map up to and including INIT_MAP_BEYOND_END */
/* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
cmpl %ebp,%eax
jb 10b
movl %edi,(init_pg_tables_end - __PAGE_OFFSET)


 #ifdef CONFIG_SMP
xorl %ebx,%ebx/* This is the boot CPU (BSP) */
jmp 3f

7、(6)init/main.c

该函数完成绝大多数的初始化,然后有0好进程init_task负责初始化过程中的全任务,包括内存管理、终端等。完成系统的初始化,将控制权交给1号进程init,该进程负责对系统剩余部分的初始化。