mov pc, r4 @ call kernel 绝对跳转到r4:40008000处开始执行
开始进入Image,Image由vmlinux生成,所以从vmlinux开始阅读理解。
arch/unicore/kernel目录,据其链接脚本,从head.S开始:
__lookup_processor_type:
运用相对取址,取出proc_info_list,做出processor对比(因为一个镜像支持一种processor,该processor的信息从协处理器的c0:4d000863中取出)。这里首先要运用相对取值,因为我们编译的内核是按照虚拟地址进行编译链接的,其次是proc_info_list的存储:我们在程序中声明了.section ".proc.info.init",而后链接脚本中显示的定义的该输入section,并且以__proc_info_begin和__proc_info_end作为界限,因此头文件的proc_info_begin结构体根本就没有相应的变量,该section的内容在编译时就确定了。
__lookup_machine_type:
验证过程同__lookup_processor_type,因为每个processor所处的环境不同,因此每个板子会有一个相应的machine_type,这在boot阶段就传入了的arch_id:0x9fc,可以与内核镜像中设定的做对比,以此来验证该内核镜像是否可以运行在该开发板上。
(查看:/arch/unicore/mach-sep0611/mach-tiger-test.c +226
/arch/unicore/include/asm/mach/arch.h +53)
__vet_atags参数地址验证
__create_page_tables:
建立内核页表(40007000处,正好据内核起始4K大小,可以建立1K个一级变换条目),因为unicore32支持4M超页,所以建立内核的页表很简单,更具内核编译的起始地址,以及结束地址bss段末尾,为内核建立页表,同时也为DDR2的虚拟地址前4M建立一级超页表映射,当然实际上有点重复了,因为我们内核的链接起始地址是C0008000,而DDR2的欲建立的虚拟起始地址是C0000000。
ldw r13, __switch_data @ address to jump to after
@ mmu has been enabled
adr lr, __enable_mmu @ return (PIC) address
add pc, r10, #PROCINFO_INITFUNC (实际上运行.section “.proc.info.init”中的b __ucv2_setup)
__ucv2_setup:
cache无效,TLB无效,将系统即将被设置的cache与MMU写入r0,我们采用了中断向量起始0xFFFF0000,I、Dcache使能,Dcache使用write_back策略,地址对其检查使能,Busrt传输使能,MMU使能(注意这些还未写进协控制寄存器),最后执行指令
mov pc,lr
因此开始运行__enable_mmu:
将页表基址写入p0.c2,相对跳转到__turn_mmu_on(注意没有改变lr寄存器值)
__turn_mmu_on:
将r0写入pc.c1 movc p0.c1, r0, #0
mov pc, r13 从此我们在虚拟地址下运行
nop; nop; nop; nop; nop; nop; nop; nop(unicore32是八级流水,不过还是多了,当然谁会在意这个呢)
__switch_data:
开始建立BSS段,将processor_id、__machine_arch_type、__atags_pointer、cr_alignment存放于固定地址(当然对这几个参数还不是很明白,以后再看看),还有一个栈值init_thread_union + THREAD_START_SP,反汇编是0xc058dff8,位于data段中,这个栈值不理解为什么要如此设置。
执行b start_kernel跳转到/init/main.c中开始执行第一个C程序。