linux0.11与linux2.6.0两个版本内核启动流程——学习笔记
Posted 西邮菜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux0.11与linux2.6.0两个版本内核启动流程——学习笔记相关的知识,希望对你有一定的参考价值。
linux学习笔记。
一、linux0.11内核启动流程
1.1 bootsect
上电后bios把bootsect放到了0x7c00的的地方;然后他自己又把自己移到了0x90000的地方,它是磁盘引导块程序,在磁盘的第一个扇区中的程序(0磁道 0磁头 1扇区 );将后续的setup.s代码从磁盘中加载到紧接着bootsect.s的地方;在显示屏上显示loading system 再将system模块加载到0x10000的地方;最后跳转到setup.s中去运行。
1.2 setup
首先解析BIOS/BOOTLOADER传递来的参数。设置系统内核运行的LDT(局部描述符) IDT(中断描述符寄存器) 全局描述符GDT(设置全局描述符寄存器)。设置中断控制芯片,进入保护模式运行(svc32保护模式 设置寄存器中的值)跳转到system模块的最前面的head.s代码运行。
1.3 head
初始化IDT、GDT,设置内存分页,跳转到main函数。
1.4 main
设置内存、缓存大小,进行内存、陷阱门、字符设备等的初始化,初始化做完后打开中断,从内核态转为用户态,利用fork创建进程1,在进程1中调用init函数,打开以终端控制台作为标准输入,之后创建标准输出、标准错误输出。调用fork创建进程2,关闭文件句柄0,以/etc/rc作为标准输入,调用execve跳转到shell代码。后面的代码只能由进程1执行了,再创建子进程,成功后关闭标准输入输出错误输出,创建新的会话期,然后重新打开/dev/tty0作为stdin,并复制成stdout和sdterr。再次执行系统解释程序/bin/sh。但这次执行所选用的参数和环境数组另选了一套。然后父进程再次运行wait()等待。这里的wait是进程1执行,所以有孤儿进程的话,他的父进程都会变为进程1。
二、linux2.6.0内核启动流程
linuxrc是一个符号链接,指向了busybox(文件系统)。
上电后CPU自检初始化然后BIOS进行硬件检测(BIOS读取启动设备第一个扇区到内存),加载内核引导程序,Linux 的 引导程序由汇编代码文件arch/i386/boot/bootsect.S生成,它利用对BIOS功能的调用将 arch/i386/boot/下的setup.S文件和内核映象加载到内存。i386的体系结构的CPU分保护模式和实模式两种,在实模式下只能使用低端的640K内存。系统在加载引导程序时CPU是处在实模式下,而现在的内核映象文件一般都超过了640K的限制,即使是经过压缩过的内核映象,这个内核映象文件通常是bzImage,我们在编译内核时通常要用到这个文件。通过循环调用bootsect_helper 将内核映象一块一块的装入内存,内核加载完成,系统跳转到setup.S的开始位置开始执行,setup.S仍在实模式下运行。设置系统参数,并为进入保护模式做准备,最后进入到保护模式并跳转到内核映象文件的头部开始执行内核。当setup.S执行完后,CPU进行保护模式,并开始执行内核,如果内核是经过压缩的,那么首先执行 arch/i386/boot/compressed目录下的head.S 建立堆栈并解压内核映象文件(arch/i386/boot/compressed/misc.c中的C函数decompress_kernel来解压内核,解压函数在startup_32中),然后再转入arch/i386/kernel下的 head.S 。没有压缩的话直接进入。解压后通过linux/arch/arm/boot/compressed目录下的Makefile寻找到vmlinux文件的链接脚本(vmlinux.lds),从中查找系统启动入口函数。得到内核入口函数为 stext(linux/arch/arm/kernel/head)。执行__lookup_processor_type(判断processor类型) -> __lookup_architecture_type (查看machine类型)->__create_page_tables(创建页表) -> __switch_data -》 __mmap_switched -> start_kernel,执行初始化。
start_kernel()继续其他方面的初始化工作,主要是初始化系统的核心数据结构,主要包括:
setup_arch():执行与体系结构相关的设置。
trap_init():设置各种入口地址。
init_IRQ():初始化IRQ中断处理机制。
sched_init():设置并启动第一个进程init_task()。
softirq_init():对软中断子系统进行初始化。
console_init():初始化控制台、显示器.
init_modules():初始化kernel_module。
fork_init():定义系统最大进程数.
最后进入rest_init()函数并调用kernel_thread()创建init内核线程,进行系统配置。
init内核线程占用进程描述表的第一项,由它来创建其他完成系统初始他的进程。
init内核线程首先要销定内核,然后调用do_basic_setup()来初始化外部设备及加载驱动程序。主
要的初始化工作包括:
PCI总线初始化。
网络初始化。
文件系统初始化。
加载文件系统。
在do_basic_setup()调用完成后,init(进程1)会释放初始化函数据占用的内存,并且打开/dev/console 设备重新定向控制台,用系统调用execve来执行用户态程序/sbin/init。至此,linux 的内核初始化工作完成。init进程是系统中所有进程的起源,init的这些工作根据/etc/inittab文件来完成,init进程产生getty进程,getty进程产生login进程,login进程又进而产生shell进程,然后我们使用shell,就可以产生每一个需要执行的进程。
系统引导完成。总结:上电后CPU加载BIOS,BIOS加载内核引导程序,内核引导程序加载压缩内核,压缩内核加载解压内核。然后执行start_kernel进行内核初始化。
以上是关于linux0.11与linux2.6.0两个版本内核启动流程——学习笔记的主要内容,如果未能解决你的问题,请参考以下文章