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进行内核初始化。

你可能感兴趣的:(linux,linux,运维,服务器)