linux内核唤醒过程,Linux内核启动过程分析

1、Linux内核启动协议

阅读文档\linux-2.6.35\Documentation\x86\boot.txt

传统支持Image和zImage内核的启动装载内存布局(2.4以前的内核装载就是这样的布局):

|            |

0A0000    +------------------------+

|  Reserved for BIOS    |    Do not use.  Reserved for BIOS EBDA.

09A000    +------------------------+

|  Command line        |

|  Stack/heap        |    For use by the kernel real-mode code.

098000    +------------------------+

|  Kernel setup        |    The kernel real-mode code.

090200    +------------------------+

|  Kernel boot sector    |    The kernel legacy boot sector.

090000    +------------------------+

|  Protected-mode kernel |    The bulk of the kernel image.

010000    +------------------------+

|  Boot loader        |   

001000    +------------------------+

|  Reserved for MBR/BIOS |

000800    +------------------------+

|  Typically used by MBR |

000600    +------------------------+

|  BIOS use only    |

000000    +------------------------+

当使用bzImage时,保护模式的内核会被重定位到0x1000000(高端内存),内核实模式的代码(boot sector,setup和stack/heap)会被编译成可重定位到0x100000与低端内存底端之间的任何地址处。不幸的是,在2.00和2.01版的引导协议中,0x90000+的内存区域仍然被使用在内核的内部。2.02版的引导协议解决了这个问题。boot loader应该使BIOS的12h中断调用来检查低端内存中还有多少内存可用。

人们都希望“内存上限”,即boot loader触及的低端内存最高处的指针,尽可能地低,因为一些新的BIOS开始分配一些相当大的内存,所谓的扩展BIOS数据域,几乎快接近低端内存的最高处了。

不幸的是,如果BIOS 12h中断报告说内存的数量太小了,则boot loader除了报告一个错误给用户外,什么也不会做。因此,boot loader应该被设计成占用尽可能少的低端内存。对zImage和以前的bzImage,这要求数据能被写到x090000段,boot loader应该确保不会使用0x9A000指针以上的内存;很多BIOS在这个指针以上会终止。

对一个引导协议>=2.02的现代bzImage内核,其内存布局使用以下格式:

|  Protected-mode kernel |

100000  +------------------------+

|  I/O memory hole    |

0A0000    +------------------------+

|  Reserved for BIOS    |    Leave as much as possible unused

~                        ~

|  Command line        |    (Can also be below the X+10000 mark)

X+10000    +------------------------+

|  Stack/heap        |    For use by the kernel real-mode code.

X+08000    +------------------------+

|  Kernel setup        |    The kernel real-mode code.

|  Kernel boot sector    |    The kernel legacy boot sector.

X      +------------------------+

|  Boot loader        |   

001000    +------------------------+

|  Reserved for MBR/BIOS |

000800    +------------------------+

|  Typically used by MBR |

000600    +------------------------+

|  BIOS use only    |

000000    +------------------------+

这里程序段地址是由grub的大小来决定的。地址X应该在bootloader所允许的范围内尽可能地低。

2、BIOS POST过程

传统意义上,由于CPU加电之后,CPU只能访问ROM或者RAM里的数据,而这个时候是没有计算机操作系统的,所以需要有一段程序能够完成加载存储在非易失性存储介质(比如硬盘)上的操作系统到RAM中的功能。这段程序存储在ROM里,BIOS就是这类程序中的一种。对于BIOS,主要由两家制造商制造,驻留在主板的ROM里。有了BIOS,硬件制造商可以只需要关注硬件而不需要关注软件。BIOS的服务程序,是通过调用中断服务程序来实现的。BIOS加载bootloader程序,Bootloader也可以通过BIOS提供的中断,向BIOS获取系统的信息。整个过程如下:

(1)电源启动时钟发生器并在总线上产生一个#POWERGOOD的中断。

(2)产生CPU的RESET中断(此时CPU处于8086工作模式)。

(3)进入BIOS POST代码处:%ds=%es=%fs=%gs=%ss=0,%cs=0xFFFF0000,%eip = 0x0000FFF0 (ROM BIOS POST code,指令指针eip,数据段寄存器ds,代码段寄存器cs)。

(4)在中断无效状态下执行所有POST检查。

(5)在地址0初始化中断向量表IVT。

(6)0x19中断:以启动设备号为参数调用BIOS启动装载程序。这个程序从启动设备(硬盘)的0扇面1扇区读取数据到内存物理地址0x7C00处开始装载。这个0扇面1扇区称为Boot sector(引导扇区),共512字节,也称为MBR。

就是说,CPU 在  BIOS 的入口(CS:IP=FFFF:0000)处执行BIOS的汇编程序,BIOS程序功能有系统硬件的检测,提供中断访问接口以访问硬件。而后被BIOS程序通过中断0x19调用磁盘MBR上的bootloader程序,将bootloader程序加载到ox7c00处,而后跳转到0x7c00,这样,位于 0x7c00处的bootloader程序,就可以执行了。

从BIOS执行MBR中的bootloader程序开始,就是linux的代码在做的事情了。

3、Bootloader过程

bootloader程序是为计算机加载(load)计算机操作系统的。boot(引导)是bootstrap的简写,bootstrap是引导指令的意思。bootloader程序通常位于硬盘上,被BIOS调用,用于加载内核。在PC机上常见的bootloader主要有grub、lilo、syslinux等。

GRUB(GRand Unified Bootloader)是当前linux诸多发行版本默认的引导程序。嵌入式系统上,最常见的bootloader是U-BOOT。这样的bootloader一般位于MBR的最前部。在linux系统中,bootloader也可以写入文件系统所在分区中。比如,grub程序就非常强大。Gurb运行后,将初始化设置内核运行所需的环境。然后加载内核镜像。

grub磁盘引导全过程:

(1)stage1: grub读取磁盘第一个512字节(硬盘的0道0面1扇区,被称为MBR(主引导记录),也称为bootsect)。MBR由一部分bootloader的引导代码、分区表和魔数三部分组成。

(2)stage1_5: 识别各种不同的文件系统格式。这使得grub识别到文件系统。

(3)stage2: 加载系统引导菜单(/boot/grub/menu.lst或grub.lst),加载内核vmlinuz和RAM磁盘initrd。

4、内核启动过程

内核映像文件vmlinuz:包含有linux内核的静态链接的可执行文件,传统上,vmlinux被称为可引导的内核镜像。vmlinuz是vmlinux的压缩文件。其构成如下:

(1)第一个512字节(以前是在arch/i386/boot/bootsect.S);

(2)第二个,一段代码,若干个不多于512字节的段(以前是在arch/i386/boot/setup.S);

(3)保护模式下的内核代码(在arch/x86/boot/main.c)。

bzImage文件:使用make bzImage命令编译内核源代码,可以得到采用zlib算法压缩的zImage文件,即big zImage文件。老的zImage解压缩内核到低端内存,bzImage则解压缩内核到高端内存(1M(0x100000)以上),在保护模式下执行。bzImage文件一般包含有vmlinuz、bootsect.o、setup.o、解压缩程序misc.o、以及其他一些相关文件(如piggy.o)。注意,在Linux 2.6内核中,bootsect.S和setup.S被整合为header.S。

initramfs(或initrd)文件:initrd是initialized ram disk的意思。主要用于加载硬件驱动模块,辅助内核的启动,挂载真正的根文件系统。

例如,我电脑上的grub启动项如下(在/boot/grub/grub.lst中):

title Fedora (2.6.35.10-74.fc14.i686)

root (hd0,0)

kernel /vmlinuz-2.6.35.10-74.fc14.i686 ro root=/dev/mapper/VolGroup-lv_root rd_LVM_LV=VolGroup/lv_root rd_LVM_LV=VolGroup/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=zh_CN.UTF-8 KEYBOARDTYPE=pc KEYTABLE=us rhgb quiet

initrd /initramfs-2.6.35.10-74.fc14.i686.img

内核的执行参数可以控制内核的行为,比如ro参数告诉内核,以只读方式挂载根分区,而quiet则告诉内核,启动的时候不要打印任何信息。这些参数不光影响内核的执行,大多数的发行版也使用这些参数控制启动完毕以后后续的动作。这些参数可以在任何时候从/proc/cmdline 这个文件中获得。现在,grub找到了内核(hd0,0)/boot/vmlinuz-2.6.35.10-74.fc14.i686,它将整个电脑的控制权交给了这个程序,内核开始进行各种初始化的动作,你可以将quiet参数去掉,以便看看内核都做了哪些事情,也可以在系统启动成功以后,使用dmesg这个命令查看内核启动的时候,都打印了哪些东西。

启动过程是和体系结构相关的,对于2.6内核,x86体系结构,CPU在上电初始化时,指令寄存器CS:EIP总是被初始化为固定值,这就是CPU复位后的第一条指令的地址。对于32位地址总线的系统来说,4GB的物理空间至少被划分为两个部分,一部分是内存的地址空间,另外一部分地址空间用于对BIOS芯片存储单元进行寻址。x86复位后工作在实模式下,该模式下CPU的寻址空间为1MB。CS:IP的复位值是FFFF:0000,物理地址为FFFF0。主板设计者必须保证把这个物理地址映射到BIOS芯片上,而不是RAM上。

装载Linux内核的第一步应该是加载实模式代码(boot sector和setup代码),然后检查偏移0x01f1处的头部(header)中的各个参数值。实模式的代码总共有32K,但是boot loader可以选择只装载前面的两个扇区(1K),然后检查bootup扇区的大小。

header���各个域的格式如下:

Offset/Size  Proto  Name    Meaning

01F1/1  ALL(1  setup_sects  The size of the setup in sectors

01F2/2  ALL  root_flags    If set, the root is mounted readonly

01F4/4  2.04+  syssize    The size of the 32-bit code in 16-byte paras

01F8/2  ALL  ram_size  DO NOT USE - for bootsect.S use only

01FA/2  ALL  vid_mode  Video mode control

01FC/2  ALL  root_dev  Default root device number

01FE/2  ALL  boot_flag  0xAA55 magic number

0200/2  2.00+  jump    Jump instruction

0202/4  2.00+  header    Magic signature "HdrS"

0206/2  2.00+  version    Boot protocol version supported

0208/4  2.00+  realmode_swtch  Boot loader hook (see below)

020C/2  2.00+  start_sys_seg  The load-low segment (0x1000) (obsolete)

020E/2  2.00+  kernel_version  Pointer to kernel version string

0210/1  2.00+  type_of_loader  Boot loader identifier

0211/1  2.00+  loadflags  Boot protocol option flags

0212/2  2.00+  setup_move_size  Move to high memory size (used with hooks)

0214/4  2.00+  code32_start  Boot loader hook (see below)

0218/4  2.00+  ramdisk_image  initrd load address (set by boot loader)

021C/4  2.00+  ramdisk_size  initrd size (set by boot loader)

0220/4  2.00+  bootsect_kludge  DO NOT USE - for bootsect.S use only

0224/2  2.01+  heap_end_ptr  Free memory after setup end

0226/1  2.02+  ext_loader_ver  Extended boot loader version

0227/1  2.02+  ext_loader_type  Extended boot loader ID

0228/4  2.02+  cmd_line_ptr  32-bit pointer to the kernel command line

022C/4  2.03+  ramdisk_max  Highest legal initrd address

0230/4  2.05+  kernel_alignment  Physical addr alignment required for kernel

0234/1  2.05+  relocatable_kernel  Whether kernel is relocatable or not

0235/1  2.10+  min_alignment  Minimum alignment, as a power of two

0236/2  N/A  pad3          Unused

0238/4  2.06+  cmdline_size  Maximum size of the kernel command line

023C/4  2.07+  hardware_subarch  Hardware subarchitecture

0240/8  2.07+  hardware_subarch_data  Subarchitecture-specific data

0248/4  2.08+  payload_offset  Offset of kernel payload

024C/4  2.08+  payload_length  Length of kernel payload

0250/8  2.09+  setup_data  64-bit physical pointer to linked list of struct setup_data

0258/8  2.10+  pref_address  Preferred loading address

0260/4  2.10+  init_size  Linear memory required during initialization

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值