linux启动(转载)

各section的位置分布看内核的链接脚本
D:/KIDE/target/kernel-version/cgel3.0/linux/include/asm-generic/vmlinux.lds.h
D:/KIDE/target/kernel-version/cgel3.0/linux/arch/powerpc/kernel/vmlinux.lds.S

Kernel镜像起始地址KERNELBASE = 0xc000 0000,这意味着内核代码和内核全局变量等的地址空间在3g-4g的地方,
而Kernel实际被boot解压到ram的0地址处。这意味着在内核没有开启mmu,将自己映射到3g开始的地址空间前,所有访问的函数地址、全局变量都要减去0xc0000000这个偏移量。


boot跳转点,kernel入口函数_start所在文件
D:/KIDE/target/kernel-version/cgel3.0/linux/arch/powerpc/kernel/head_32.S
链接脚本的起始符号_stext就是从这个文件开始,各类异常处理入口也在这个文件里。

保存boot传过来的r3,r4到r31和r30,给r24赋0;
r3:扁平设备树首地址,物理地址。
r4中是什么?可能是被boot解压的首地址,603好像没用到。
r24干什么的?多核初始化使用,放的是核的编号

执行early_init:
early_init位于.init.text段,这是一个c语言的函数,堆栈指针r1未见到在之前的代码中指定,应该是延用的boot跳过来时使用的值。

reloc_offset这个函数比较巧妙,使用一个链接时确定的绝对地址,利用相对跳转到那里得到当前运行的实际地址,计算差值从而求出当前kernel被解压的地方距离0xc000 0000的偏移。
这要是保证即使kenel没有被boot解压到0地址,代码也能正常运行。

清bss段,注意如何确定现在的Bss段起始地址。在kernel没有把自己映射到0xc0000000时,所有的全局符号访问都要算偏移。

memset_io比普通的memset多了flush cache的操作,保证写到ram中。

SPRN_PVR是处理器的version register,identify_cpu函数根据读出的SPRN_PVR值在全局结构体数组cpu_specs中匹配cpu类型,cc是ppc603.
匹配成功,cur_cpu_spec指向cpu_specs中ppc603那一数组成员。

do_feature_fixups这个函数先解释他的后两个入参,__start___ftr_fixup是__ftr_fixup段的起始地址,__stop___ftr_fixup是__ftr_fixup段的结束地址。
__ftr_fixup这个段的内容其实是一个数组,每个数组成员是一个结构体,该结构体描述了某段代码的起始地址,结束地址,还有特殊的值及掩码作为标识。
使用BEGIN_FTR_SECTION,END_FTR_SECTION_IFSET这两个宏包住的汇编代码会在__ftr_fixup段里记录这段汇编代码的相关位置及标识信息。
这两个宏包住的代码都是一些和cpu特性相关的代码,如果cpu使用这些特性就执行,如果cpu不使用这些特性,do_feature_fixups则根据__ftr_fixup段里的信息,找到这些代码,
把所有指令都换成NOP,达到屏蔽相关流程的目的。
cpu使用哪些特性,在cur_cpu_spec->cpu_features中记录,是一个掩码值。

early_init最后返回Kernel当前运行的实际地址。

mmu_off:设置msr的ir和dr关闭mmu,并跳到__after_mmu_off。此处可以看出隐性要求kernel被解压的物理地址==虚拟地址。

clear_bats:清零几对bat寄存器。bat模式的mmu比起页表模式mmu来说简单很多。相关的只有几对寄存器,两个寄存器为一对,一对bat寄存器的信息包括某个地址开始的虚拟地址对应的
物理地址,映射范围,访问属性等。一对bat寄存器映射范围最大256m。指令和数据有单独的bat寄存器对。mmu开启时,bat优先于页表模式,即先在bat寄存器中命中虚地址。
这个函数是一个典型的__ftr_fixup段的应用。注意BEGIN_FTR_SECTION,END_FTR_SECTION_IFSET这两个宏。

flush_tlbs:清页表方式mmu的快表。

initial_bats:初始化bat寄存器,目的是建立0地址到0xc0000000的映射。映射了256m的大小。
注意tophys这个宏,内核由于一定要将自己扔在物理0地址,因此在内核里虚拟地址减去0xc0000000就是物理地址。
这个宏除了做这个转化外,还将转化指令的地址存在了.vtop_fixup段,这样做的用处是在需要改变这种映射关系时,把.vtop_fixup段里指示的所有指令都替换就可以了。
ppc603好像不会用这个段,因为要保证异常向量的地址在0x100等地方,内核一定要放在0地址处,所以内核里虚实地址对应的关系是不会变的。


reloc_offset:再调用一次确保r3中存放的是当前实际地址与0xc0000000的偏移。

call_setup_cpu:从cur_cpu_spec指向的结构体中取出cpu setup函数的指针执行。ppc603对应的函数是__setup_cpu_603。
__setup_cpu_603仅仅调用setup_common_caches使能cache。

init_idle_6xx:设置hid0里电源管理相关的一些位。
e300支持的电源管理的模式Full-Power Mode、Doze Mode、Nap Mode、Sleep Mode。我们应该是Full-Power Mode。啥都不干直接返回了。
这里也能看到__ftr_fixup段的应用。


如果内核是被boot解压到0地址,则直接去开启mmu,不然要执行relocate_kernel。
relocate_kernel:将内核拷贝到0地址去,Linux的硬性要求。原因也很明显,要保证异常处理程序所处的位置。看看head32.S里如何使用.符号进行的内存布局可以有更深了解。
klimit = _end,镜像结束地址。relocate_kernel先拷贝0x4000大小的内容到0地址,估计是因为拷贝函数copy_and_flush本身就处在0x4000内。拷过去后就能够使用0地址开始的代码运行了。


turn_on_mmu:开启mmu,因为我们已经使用bat寄存器进行了0到0xc0000000地址256m的映射,这之后终于可以不用管偏移问题了。内核里的代码和全局变量都能正常访问了。跳转到start_here,真正开始内核的运行。

在head32.s的代码段布局中,以上函数的指令只到head32.o的0x6c处,后面代码依次放的是smp另外核的初始化、各类异常处理入口函数、AltiVec指令集支持(好像是指专门的浮点指令集)。
在我们cc的配置下,initial_bats是head32.o的最后一个函数,最后一条指令只到偏移0x35bc处。

start_here:
系统初始进程控制块init_task,里面的thread_struct结构字段thread存放CPU相关的信息,譬如堆栈、寄存器等。把thread字段的物理地址存入sprg3,

Kernel command line: root=/dev/ram rw console=ttyS0,9600 mem=224M

 


__setup("root=", root_dev_setup);
__setup("rw", readwrite);
__setup("console=", console_setup);
early_param("mem", early_parse_mem);

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值