linux内核启动过程

linux启动过程:
1、BIOS:将启动扇区加载到内存并执行
  当计算机加电自检时,发RESET到CPU,IP指向物理地址0xfffffff0开始执行。由硬件将0xfffffff0映射到ROM,ROM中存放BIOS服务。加电后CPU处于实模式,所以BIOS中为实模式代码。
  BIOS将启动设备的第一扇区区加载到物理地址0x00007c00处,第一扇区通常放的是MBR,MBR查找ACTIVE分区并读入该分区的boot sector,一般是bootloader
2、bootloader:将OS装入内存并执行
  将实模式代码装入内存,包括bootsect和setup
  将保护模式代码装入内存,小内核镜像zImage装入0x10000(loaded low),大内核镜像bzImage装入0x100000(loaded high)。
  跳转到setup
3、setup:初始化设备,切换到保护模式
  初始化设备,设置页表,切换到保护模式
  跳转到startup_32/startup_64执行保护模式代码
4、startup_32/startup_64:初始化
  如果是压缩内核,则解压缩内核后再跳转到解压后的startup_32/startup_64
  初始化
  跳转到start_kernel
5、start_kernel:启动内核
6、init进程


linux内核的启动过程主要是:
1、setup的执行
2、内核的解压缩
3、解压后内核的初始化
4、内核的启动
5、init启动

1、setup的执行
bootloader装入实模式和保护模式代码后,首先将控制权交给实模式入口-实模式加载位置偏移512:
Documentation/x86/boot.txt

    143 The first step in loading a Linux kernel should be to load the
    144 real-mode code (boot sector and setup code) and then examine the
    145 following header at offset 0x01f1.  The real-mode code can total up to
    146 32K, although the boot loader may choose to load only the first two
    147 sectors (1K) and then examine the bootup sector size.
    
    910 **** RUNNING THE KERNEL
    911 
    912 The kernel is started by jumping to the kernel entry point, which is
    913 located at *segment* offset 0x20 from the start of the real mode
    914 kernel.  This means that if you loaded your real-mode kernel code at
    915 0x90000, the kernel entry point is 9020:0000.



setup.bin是实模式的16位代码,是内核最先拿到控制权的部分,setup的链接脚本如下:
arch/x86/boot/setup.ld:

 10 SECTIONS
 11 {
 12         . = 0;
 13         .bstext         : { *(.bstext) }
 14         .bsdata         : { *(.bsdata) }
 15 
 16         . = 497;
 17         .header         : { *(.header) }
 18         .entrytext      : { *(.entrytext) }
 19         .inittext       : { *(.inittext) }
 20         .initdata       : { *(.initdata) }
 21         __end_init = .;



可以得出实模式内核第一条执行指令位于.header块中

arch/x86/boot/header.S:

 94         .section ".header", "a"
 95         .globl  hdr
 96 hdr:
 97 setup_sects:    .byte 0                 /* Filled in by build.c */
 98 root_flags:     .word ROOT_RDONLY
 99 syssize:        .long 0                 /* Filled in by build.c */
100 ram_size:       .word 0                 /* Obsolete */
101 vid_mode:       .word SVGA_MODE
102 root_dev:       .word 0                 /* Filled in by build.c */
103 boot_flag:      .word 0xAA55
104 
105         # offset 512, entry point
106 
107         .globl  _start
108 _start:
109                 # Explicitly enter this as bytes, or the assembler
110                 # tries to generate a 3-byte jump here, which causes
111                 # everything else to push off to the wrong offset.
112                 .byte   0xeb            # short (2-byte) jump
113                 .byte   start_of_setup-1f



 

setup相应的处理完成后会切换成保护模式,并将跳转到startup_32/startup_64执行
start_of_setup(arch/x86/boot/header.S)->main(arch/x86/boot/main.c)->go_to_protected_mode(arch/x86/boot/pmjump.S)->startup_BITS(arch/x86/boot/compressed/head_32.S)
其中startup_BITS位置存放在实模式内核头的code32_start字段里,bzImage的默认值是0x100000


2、内核的解压缩
1、内核自解压代码(arch/x86/boot/compressed/misc.c)将装入内存中的压缩内核向后移未压缩内核大小并自解压将内核解压到code32_start处;
2、解析elf格式的内核
3、跳转到解压后内核的入口startup_32/startup_64
startup_32->decompress_kernel->parse_elf->jmp

3、解压后内核的初始化
解压后的内核代码入口为:
arch/x86/kernel/header_32.S
startup_32->i386_start_kernel->start_kernel

4、内核的启动
init/main.c
start_kernel

5、init启动
start_kernel->rest_init->kernel_init->init_post->run_init_process

 

你可能感兴趣的:(linux,kernel)