免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2587 | 回复: 5
打印 上一主题 下一主题

Understanding the linux kernel附录-内核启动过程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-10 21:50 |只看该作者 |倒序浏览
下面是我翻译的中文译文,有两个问题,有点想不通,请大家帮忙。
1,如果我系统为win和Linux,并且grub装在MBR(磁盘的第一个扇区),上,那么原来的win的启动时程序被grub覆盖了,怎么还能启动win呢?
2,如果我系统为win和Linux,并且grub装在Linux分区的BootSector上,那么grub是如何启动的?因为上电后,bios会读入MBR(磁盘的第一个扇区),而不是Linux分区的grub所在的扇区。我猜想是不是和活动分区表有关呢?



附录A 系统启动过程这部分附录内容解释了在用户接通计算机电源之后,具体发生了什么事情  也就是Linux内核映像如何被拷贝到内存并执行的。  简而言之,我们将讨论内核也就是整个系统,如何启动的。如何[bootstrapped]

传统上来说,[bootstrap]的意思为一个人打算穿上鞋站起来。在操作系统术语中,这个词代表着至少  要把操作系统的一部分(或者全部)载入到内存,并且使处理器开始执行它。  它也代表着对内核数据结构的初始化和一些用户进程的创建过程,并且将控制权转移到其中的某一个用户进程。

计算机的[bootstrap]是一个冗长乏味的工作,因为在初期(系统上电),几乎每个硬件设备,包块RAM,都处在随机的不可预知的状态。而且[bootstrap]过程十分依赖计算机的体系结构。就像本书中通常一样。我们介绍80X86的启动过程。

A.1.史前时代:BIOS 刚刚上电之后,计算机实际上是无用的,因为RAM芯片中的值是随机的并且没有操作系统在运行。为了开始 boot。一种特殊的硬件电路(RESET电路),向CPU的RESET引脚发出RESET信号。CPU接收到RESET信号,会将一些寄存器设定固定值(包括CS 和EIP),然后从物理地址0xfffffff0开始执行。这个地址被映射到ROM。存储在ROM中0xfffffff0地址的程序通常被称为Basic Input/Output System (BIOS)。在X86体系结构中,因为BIOS包含了几个中断驱动的低级的过程,这个过程可以被任何的操作系统用于在boot阶段来控制硬件设备。一些操作系统例如MS-DOS,依赖BIOS实现所有的系统调用。

一旦进入了保护模式,Linux就不再使用BIOS了,而是为每个硬件提供自己的设备驱动程序。事实上,BIOS程序必须执行在实模式下,因此无法共享一些功能(函数),即使共享会带来好处。(这里不太理解)

BIOS使用实模式的地址空间,因为在计算机开机之后,只有他们才是可用的。实模式地址由段地质和段内的偏移组成对应的物理地址为段地址*16 +段内偏移,因此CPU的寻址单元将逻辑地址转换位物理地址的时候,不需要全局描述符表。局部描述符表,页表。很明显,初始化全局描述符表,局部描述符表和页表的代码必须在实模式下。

Linux在[bootstrap]阶段需要使用BIOS,来找到内核映像在磁盘中(或者其他外部设备)的位置。BIOS bootstrap 实际上完成了下面四项的工作: 1,执行一系列检测硬件的命令,目的是确定哪些设备安装在了计算机上,它们是否工作正常。这个阶段通常被称为Power-On Self-Test (POST) 在这个阶段中,一些信息,如BIOS的版本号,被通过显示器显示出来。

2,初始化应建设备。这个阶段对于现代基于PCI体系的系统非常关键,因为其 允许所有的硬件设备在没有配置之前使用中断请求和输入/输出端口。在这个阶段结束之后,会表示出来已经安装的PCI设备。

3,查找一个操作系统来启动,实际上依赖BIOS的设定。BIOS也许尝试(预定义的顺序,或者通过用户定制)软盘的第一个扇区,硬盘的第一个扇区,光盘的第一个扇区。 4,只要找到一个有效的设备,bios就把第一个扇区的内容拷贝到内存0x7c00。并且挑砖到该地址开始执行。

本附录的其他内容将带你领略Linux系统的基本的启动状态到系统的完全运行的过程。

A.2远古时代:BootLoader(启动程序)启动程序由BIOS调用,它将操作系统的内核映像载入内存。让我们来简要勾勒一下在IBM的PC上,BootLoader是如何工作的为了使用软盘启动,存储在软盘第一个扇区的内容被拷贝到内存并且执行。这些指令将内核映像的其它扇区拷贝到内存。

而从硬盘启动就会有一些不同。硬盘的第一个扇区被称为MBR,MBR包含分区表和一个小程序。这个小程序将把包含用户想要启动操作系统的分区的第一个扇区拷贝到内存。例如WIN98,通过在分区表中的活动标志来选择哪个分区是活动的。也就是说,只有操作系统的内核映像载活动分区中,那个它才有可能被启动。

Linux使用更加灵活的方式,因为它替换了原来MBR中的原始程序,而是用成熟的BootLoader程序。BootLoader允许用户选择想要启动哪个操作系统。 2.4版本以前的内核,一如既往的包含了一个小的BootLoader程序,在第一个512字节中。因此把从软盘把内核拷贝到内存,从而可以启动系统。然而,从2.6版本开始,内核不再包含此BootLoader,因此如果想要从一个软盘启动,那么就需要把合适的BootLoader存储在软盘的第一个分区。现在,从软盘启动和从硬盘启动。光盘启动基本都一致了。

A2.1从硬盘启动为了从硬盘启动,需要一个two-stage的BootLoader. 如LILO ,GRUB要比LILO先进,因为它可以识别几种文件系统,因此可以从文件中读取部分启动程序。当然,存在一些特殊的BootLoader可以支持Linux支持的所有的体系结构。

LILO或者被安装在MBR,或者被安装在任何活动分区的BootSector,两种情况的最终结果都是一样的。当Loader执行的时候,用户必须选择启动哪个系统。

实际上。LILO BootLoader程序超过了一个扇区(512字节)因此它分为两部分,安装在MBR或者某个分区的BootSector中的小启动程序。这个小启动程序由BIOS拷贝到内存0X7C00。然后它将自己搬运到0X96A00。设置实模式的栈(0X98000 --0X969FF) 然后再把另外一部分的LILO BootLoader程序拷贝到0X96C00,并调转到0X96C00开始执行。后面的这个程序从硬盘读取可以启动的 的操作系统,并由用户选择。  最终,LILLO BootLoadre或者把对应的某个分区的BootSector拷贝到内存,或者把内核映像拷贝到内存。  LILO实际上做了下面的工作:  1,调用BIOS的例程,表示Loading 信息。  2,调用BIOS例程,把内核映像前512字节拷贝到0X90000地址。而setup()函数的地址为0X90200。  3,调用BIOS例程,将内核映像的其他部分从硬盘 拷贝到内存0X10000(或者0X10000,对于大内核)。  4,跳转到setup()函数

论坛徽章:
0
2 [报告]
发表于 2008-07-11 20:47 |只看该作者

回复 #1 chenbdchenbd 的帖子

怎么没人回复呢?求高手解答。

A.3中古时代:setup()函数 setup()汇编语言函数的代码被链接器配置到内核映像文件内的偏移0X200处。因此BootLoader可以轻松的找到它,并且把它拷贝到内存的0X90200地址。 setup()函数必须要初始化计算机的所有硬件设备,并且为内核的执行构建好环境。虽然BIOS已经初始化了所有硬件设备,但是Linux并不依靠BIOS,而是使用自己的方式重新初始化硬件设备,因而来提供程序的可移植性和健壮性。

setup()实际上做了下面的工作:
1,对于ACPI(什么是ACPI,不了解)兼容的系统,调用BIOS的例程在物理内存中建立一张描述系统物理内存的表。在比较老的系统中,只是简单的调用BIOS的例程来获取系统可用内存的数量。
2,设定键盘的重复延迟和比率(当用户按下一个按键一段时间,键盘控制器会把按键对应的键位码一遍又一遍的发送给CPU)。
3,初始化图形适配卡。
4,初始化硬盘控制器,并且获得硬盘参数(具体都有什么,不了解)。
5,检查IBM微通道总线(MCA)。
6,检查PS/2指点设备。
7,检查高级电源管理(APM,不太了解)的BIOS支持。
8,如果BIOS支持增强的磁盘驱动服务(EDD,不太了解),那么调用适当的BIOS例程在内存中建立一张用来描述可用硬盘的表。(表中包含的信息可以通过读取 sysfs特殊文件系统的 firmware/edd目录察看)。
9,如果内核映像被装载到0X10000,那么就把内核移动到0X1000。相反,如果内核映像被装载到0X100000,则不进行移动。这个过程是必需的,因为为了能使用软盘保存内核映像和缩短boot时间(这里不太了解),存储在硬盘上的内核映像是被压缩过的。而解压缩过程需要内存中,在内核的映像的后面存在空闲空间来作为临时的缓冲区。
10,设定8042键盘控制器的A20引脚。A20引脚作为一个hack(hack不太清楚如何翻译)在80286及其后来的系统中被引入。作用是为了保持和早期8088的系统保持兼容。不幸的是,在进入到保护模式之前,必须要正确设定A20引脚。否则第20根以后的地址线将总是被CPU当作0,设定A20引脚是一个凌乱的过程。
11,建立一个临时的中断描述符表(IDT)和临时的全局描述符表(GDT)。
12,如果有浮点单元,重新设定。
13,关中断。除了IRQ2(我想是两个8259A级联,使用IRQ2)。
14,设置CR0中的PE标志位。从实 模式切换到保护模式。这时,CR0的PG标志位依然没有被设定,所以分页依然没有启用。
15,跳转到汇编语言函数startup_32( )。arch/i386/boot/compressed/head.S 。

A.4文艺复兴时代:
startup_32( ) 函数存在两个版本的startup_32( ) 函数,我们现在所指的是arch/i386/boot/compressed/head.S 文件中的startup_32( )函数。 setup()函数执行结束之后,startup_32()函数已经被移动到了0X100000(loaded high)地址,或者0X1000(loaded low)地址。

startup_32( ) 函数实际上完成下面工作:
1,初始化各个段寄存器和一个临时的栈。
2,清除EFLAG寄存器中的所有位。
3,将内核未初始化数据清0(未初始化数据从_edata 开始,到_end结束)。
4,调用decompress_kernel( )函数解压内核映像。首先表示"Uncompressing Linux..."信息,当解压完成后,the "O K, booting the kernel." 信息被表示。解压后的内核被放在0x00100000(loaded low),或者内核映像的后面(loaded high).然后将解 压后的内核搬运到最终的位置:0x00100000。
5,跳转到0x00100000。

解压后的内核映像以arch/i386/kernel/head.S 文件中的startup_32( ) 函数作为开始。使用两个同名字的函数不会产生实际的问题,除了使读者赶到困惑之外,因为这两个函数的执行都是通过跳转到初始地址来实现的。

后一个startup_32( ) 函数,为0号进程设置好执行环境。此函数中进行了下面的操作:
1,初始化段寄存器为最终的值。
2,填充内核的bss段(BSS段,不太了解)为0。
3,初始化内核临时页表(保存在swapper_pg_dir 和pg0),把逻辑地址映射为相同的物理地址。
4,在CR3寄存器中,保存全局页表目录(PGD),并把CR0中的PE标志位置1,启动分页。
5,为0号进程设定好内核模式栈。
6,清除EFLAG标志寄存器中的所有位。
7,调用setup_idt( )函数,将中断向量表填充为中断向量。
8,将从BIOS得到的系统参数和传递给系统的参数,保存在第一页中。
9,设别处理器的类型。
10,将全局描述符表的地址和中断描述符表的地址分别载入GDTR 和 IDTR寄存器。
11,跳转到start_kernel( )函数。

A.5现代:start_kernel()函数

start_kernel()函数完成对内核的初始化。几乎内核的所有组件都是被start_kernel()函数初始化的。

这里仅仅介绍其中的几个:

1,调度器通过sched_init()函数初始化。

2,内存区域通过函数build_all_zonelists()函数初始化。

3,buddy系统分配器通过page_alloc_init()和mem_init()函数初始化。

4,中断向量表通过trap_init()函数初始化。

5,TASKLET_SOFTIRQ和HI_SOFTIRQ通过softirq_init()函数初始化。

6,系统时间和日期通过time_init()函数初始化。

7,slab分配器通过kmem_cache_init()函数初始化。

8,cpu时钟通过calibrate_delay()函数决定。

9,通过kernel_thread()函数,创建1号进程。1号进城创建其它内核线程并且执行/sbin/init程序。

除了在start_kernel()函数开始表示"Linux version 2.11...”的信息外,在这个过程中,很对信息通过内核线程和init程序被表示出来。最终,通常的login提示在控制台(或者图形界面)表示。告诉用户登陆,linux内核已经开始运行了。

论坛徽章:
0
3 [报告]
发表于 2008-07-22 20:25 |只看该作者

回复 #2 chenbdchenbd 的帖子

等了好几天了,也没人回复阿:em11:

论坛徽章:
0
4 [报告]
发表于 2008-10-23 17:10 |只看该作者
1,如果我系统为win和Linux,并且grub装在MBR(磁盘的第一个扇区),上,那么原来的win的启动时程序被grub覆盖了,怎么还能启动win呢?

启动时进入grub交互界面
root (hdx,x)         //指定你windows的系统所在的分区
chainloader +1   

2,如果我系统为win和Linux,并且grub装在Linux分区的BootSector上,那么grub是如何启动的?因为上电后,bios会读入MBR(磁盘的第一个扇区),而不是Linux分区的grub所在的扇区。我猜想是不是和活动分区表有关呢?

这个半懂。 我理解的是 mbr中也需IPL,然后IPL把控制权交给grub

论坛徽章:
0
5 [报告]
发表于 2008-10-23 21:05 |只看该作者
第一个问题应该就是楼上回答的那样。
第二种情况应该是MBR给出了BootSector的地址,并把控制权交了了它

论坛徽章:
0
6 [报告]
发表于 2008-10-23 21:14 |只看该作者
启动这部分有点意思,里面有不少错字
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP