Linux启动过程代码分析
1,入口函数和链接地址
从链接脚本中可以找到入口函数,Linux内核的链接脚本arch/arm/kernel/vmlinux.lds是由arch/arm/kernel/vmlinux.lds.S这个汇编文件生成的。
从链接脚本可以得出内核的入口函数为stext函数,在arch/arm/kernel/head.S中。
从链接脚本还可以的出,内核的链接地址为0xc0008000。
2,head.S文件分析
首先定义两个宏,这两个宏分别是内核起始地址的虚拟地址和物理地址,分别为0xC0008000和0x30008000。
地址检测,内核地址必须从0xXXXX8000开始
重要的注释:
/*
* Kernel startup entry point.
* ---------------------------
*
* This is normally called from the decompressor code. The requirements
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
* r1 = machine nr, r2 = atags pointer. 内核启动条件 :1,MMU=off,D-cache=off;2,r0=0,r1=硬件号,r2=内核传参的地址
*
* This code is mostly position independent, so if you link the kernel at
* 0xc0008000, you call this at __pa(0xc0008000). 内核的链接地址是虚拟地址0xc0008000,但是mmu 关闭了,所以没开启mmu 之前要用地址无关码可以通过__pa()函数得到虚拟地址对于的物理地址
*
* See linux/arch/arm/tools/mach-types for the complete list of machine
* numbers for r1. uboot通过r1 传递的机械码可以在linux/arch/arm/tools/mach-types目录查找
*
* We're trying to keep crap to a minimum; DO NOT add any machine specific
* crap here - that's what the boot loader (or in extreme, well justified
* circumstances, zImage) is for. zImage是压缩后的内核,uboot跳转到的地址其实是一段解压缩的代码,然后才运行内核
*/
汇编阶段
__HEAD,表示下面的代码在一个自定义断。
注释:如果uboot的memtags或bootargs传参错误,内核将无法启动;
这里建立的映射页表是一个段式页表(16K),后面会再次建立细页表并舍弃这个段式页表。
将栈指针指向__mmap_switched,__mmap_switched是一个函数指针。
并将lr返回寄存器设置成__enable_mmu函数的地址。
执行__enable_mmu函数,使能mmu
继续指向__turn_mmu_on函数,操作cp15的control寄存器
同时将pc指针指向r13栈指针寄存器,这个寄存器之前存放了__mmap_switched函数的地址,所以这里远跳转到 __mmap_switched函数
** __mmap_switched函数:复制数据段、清bss段、保存处理器ID、机器码、uboot传参指针。最后执行start_kernel函数,执行C代码。**
setenv bootargs 'console=ttySAC2,115200 root=/dev/mmcblk0p3 rw init=/linuxrc rootfstype=ext3'
setenv bootargs 'root=/dev/nfs nfsroot=192.168.6.99:/root/rootfs ip=192.168.6.66:192.168.6.99:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200 '
阅读原子linux开发pdf笔记