⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux启动分析.txt

📁 9200的开发资料:包括uboot
💻 TXT
📖 第 1 页 / 共 2 页
字号:
引导Linux通常有两种方法,一种是由MILO及其他类似的引导程序引导,另一种是由Firmware直接引导。
“arch/alpha/boot”下就是制作Linux Bootloader的文件。“head.S”文件提供了对 OSF PAL/1的调用入口,它将被编译后置于引导扇区(ARC的分区首扇区或SRM的磁盘0扇区),得到控制后初始化一些数据结构,再将控制转给“main.c”中的start_kernel(), start_kernel()向控制台输出一些提示,调用pal_init()初始化PAL代码,调用openboot() 打开引导设备(通过读取Firmware环境),调用load()将核心代码加载到START_ADDR(见 “include/asm-alpha/system.h”),再将Firmware中的核心引导参数加载到ZERO_PAGE(0) 中,最后调用runkernel()将控制转给0x100000的kernel,bootloader部分结束。

“arch/alpha/boot/bootp.c”以“main.c”为基础,可代替“main.c”与“head.S” 生成用于BOOTP协议网络引导的Bootloader。 
Bootloader中使用的所有“srm_”函数在“arch/alpha/lib/”中定义。

以上这种Boot方式是一种最简单的方式,即不需其他工具就能引导Kernel,前提是按照 Makefile的指导,生成bootimage文件,内含以上提到的bootloader以及vmlinux,然后将 bootimage写入自磁盘引导扇区始的位置中。

当采用MILO这样的引导程序来引导Linux时,不需要上面所说的Bootloader,而只需要 vmlinux或vmlinux.gz,引导程序会主动解压加载内核到0x1000(小内核)或0x100000(大内核),并直接进入内核引导部分,
bbbbbbbbbbbbbbbbbbbbbbb

arch/alpha/vmlinux.lds的链接脚本控制下,链接程序将vmlinux的入口置于 "arch/alpha/kernel/head.S"中
的__start上,因此当Bootloader跳转到0x100000时, __start处的代码开始执行。__start的代码很简单,
只需要设置一下全局变量,然后就跳转到start_kernel去了。
start_kernel()是"/init/main.c"(体系结构无关)中的asmlinkage函数。
至此,启动过程转入体系结构无关的通用C代码中。


--> 对arm平台
arch/arm/kernel/head-armv.s(32bit)(head-armo.s(26bit))
里面有一句add	pc, r10, #12
r10=__proc_info_end(脚本里面定义arch\arm\vmlinux-armo.lds.in(17))
里面包含arm\mm\proc-arm920.S(645)
r10调整12就是指向结构体里面的一个一条语句	b	__arm920_setup
--<


start_kernel()中调用了一系列初始化函数,以完成kernel本身的设置。这些动作有的是公共的,有的则是需要配置的才会执行的。

在start_kernel()函数中, 
输出Linux版本信息(printk(linux_banner)) 
设置与体系结构相关的环境(setup_arch()) 
页表结构初始化(paging_init()) 
使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口(trap_init()) 
使用alpha_mv结构和entry.S入口初始化系统IRQ(init_IRQ()) 
核心进程调度器初始化(包括初始化几个缺省的Bottom-half,sched_init()) 
时间、定时器初始化(包括读取CMOS时钟、估测主频、初始化定时器中断等,time_init()) 
提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,(parse_options()) 
控制台初始化(为输出信息而先于PCI初始化,console_init()) 
剖析器数据结构初始化(prof_buffer和prof_len变量) 
核心Cache初始化(描述Cache信息的Cache,kmem_cache_init()) 
延迟校准(获得时钟jiffies与CPU主频ticks的延迟,calibrate_delay()) 
内存初始化(设置内存上下界和页表项初始值,mem_init()) 
创建和设置内部及通用cache("slab_cache",kmem_cache_sizes_init()) 
创建uid taskcount SLAB cache("uid_cache",uidcache_init()) 
创建文件cache("files_cache",filescache_init()) 
创建目录cache("dentry_cache",dcache_init()) 
创建与虚存相关的cache("vm_area_struct","mm_struct",vma_init()) 
块设备读写缓冲区初始化(同时创建"buffer_head"cache用户加速访问,buffer_init()) 
创建页cache(内存页hash表初始化,page_cache_init()) 
创建信号队列cache("signal_queue",signals_init()) 
初始化内存inode表(inode_init()) 
创建内存文件描述符表("filp_cache",file_table_init()) 
检查体系结构漏洞(对于alpha,此函数为空,check_bugs()) 
SMP机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP的内核,此函数为空,smp_init()) 
启动init过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle() 等待调度,rest_init()) 
至此start_kernel()结束,基本的核心环境已经建立起来了。


/init/main.c中
init()函数作为核心线程,首先锁定内核(仅对SMP机器有效),
然后调用 do_basic_setup()完成外设及其驱动程序的加载和初始化。过程如下:

do_basic_setup:
总线初始化(比如pci_init()) 
网络初始化(初始化网络数据结构,包括sk_init()、skb_init()和proto_init()三部分,在proto_init()中,将调用protocols结构中包含的所有协议的初始化过程,sock_init()) 
创建bdflush核心线程(bdflush()过程常驻核心空间,由核心唤醒来清理被写过的内存缓冲区,当bdflush()由kernel_thread()启动后,它将自己命名为kflushd) 
创建kupdate核心线程(kupdate()过程常驻核心空间,由核心按时调度执行,将内存缓冲区中的信息更新到磁盘中,更新的内容包括超级块和inode表) 
设置并启动核心调页线程kswapd(为了防止kswapd启动时将版本信息输出到其他信息中间,核心线调用kswapd_setup()设置kswapd运行所要求的环境,然后再创建 kswapd核心线程) 
创建事件管理核心线程(start_context_thread()函数启动context_thread()过程,并重命名为keventd) 
设备初始化(包括并口parport_init()、字符设备chr_dev_init()、块设备 blk_dev_init()、SCSI设备scsi_dev_init()、网络设备net_dev_init()、磁盘初始化及分区检查等等,device_setup()) 
执行文件格式设置(binfmt_setup()) 
启动任何使用__initcall标识的函数(方便核心开发者添加启动函数,do_initcalls()) 
文件系统初始化(filesystem_setup()) 
//安装root文件系统(mount_root()) 
至此do_basic_setup()函数返回init(),在释放启动内存段(free_initmem())并给内核解锁以后,init()打开/dev/console设备,重定向stdin、stdout和stderr到控制台,最后,搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用 execve()系统调用加载执行init程序。 
prepare_namespace

init()函数到此结束,内核的引导部分也到此结束了,这个由start_kernel()创建的第一个线程已经成为一个用户模式下的进程了。此时系统中存在着六个运行实体:

start_kernel()本身所在的执行体,这其实是一个"手工"创建的线程,它在创建了init()线程以后就进入cpu_idle()循环了,它不会在进程(线程)列表中出现 
init线程,由start_kernel()创建,当前处于用户态,加载了init程序 
kflushd核心线程,由init线程创建,在核心态运行bdflush()函数 
kupdate核心线程,由init线程创建,在核心态运行kupdate()函数 
kswapd核心线程,由init线程创建,在核心态运行kswapd()函数 
keventd核心线程,由init线程创建,在核心态运行context_thread()函数 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -