1. uboot引导内核的必要条件
// 推荐一本书 Booting ARM Linux.pdf ,可在网络搜索.
Configure the memory system.
Load the kernel image at the correct memory address.
Optionally load an initial RAM disk at the correct memory address.
Initialise the boot parameters to pass to the kernel.
Obtain the ARM Linux machine type
Enter the kernel with the appropriate register values.
1.配置内存系统
2.加载内核映像到正确的内存地址
//可选择在正确的内存地址加载初始RAM磁盘。
3.初始化引导参数,并将地址写到r2
4.获取ARM Linux机器类型,并写到r1
5.r0 为0
6.让内核运行
通常除了这些基本任务外,引导加载程序还会为内核初始化一个串行或视频控制台。实际上,在大多数系统配置中,串行端口几乎被认为是必需的。
2.1如果uboot 引导了一个压缩的内核
像以下内核镜像都是被压缩的,压缩格式可以为 GZIP,LZO,LZMA,当前为gzip.
arch/arm/boot/compressed/vmlinux
arch/arm/boot/zImage
arch/arm/boot/uImage
这些文件的组成如下
1.前缀
2.解压代码
3.gzip压缩的二进制内核
入口
linux的第一行代码从 linux-3.0.1/arch/arm/boot/compressed/head.S 中的 start 标号地址的 mov r0, r0 开始
出口
到 mov pc, r4 跳转到 linux-3.0.1/arch/arm/kernel/head.S 中的 75行 ENTRY(stext)
linux-3.0.1/arch/arm/boot/compressed/head.S 中 115 行
.section ".start", #alloc, #execinstr // line 115
start:
.type start,#function
.rept 7
mov r0, r0
.endr
...
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
...
/*
* The C runtime environment should now be setup sufficiently.
* Set up some pointers, and start decompressing.
* r4 = kernel execution address
* r7 = architecture ID
* r8 = atags pointer
*/
mov r0, r4
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max
mov r3, r7
bl decompress_kernel
bl cache_clean_flush
bl cache_off
mov r0, #0 @ must be zero
mov r1, r7 @ restore architecture number
mov r2, r8 @ restore atags pointer
mov pc, r4 @ call kernel
这里不讲述linux-3.0.1/arch/arm/kernel/head.S 的意图
2.2如果uboot 引导了一个未压缩的内核
// 这些文件都是没被压缩的.
vmlinux // 该文件在编译过程中,生成与顶层目录,和 arch/arm/boot/compressed/vmlinux 有区别
arch/arm/boot/Image
入口
linux-3.0.1/arch/arm/kernel/head.S 中的 75行 ENTRY(stext)
出口过程 // TODO
ldr r13, =__mmap_switched @ address to jump to after
adr lr, BSYM(1f) @ return (PIC) address
add pc, r10, #PROCINFO_INITFUNC
r10 是 变量 __v6_proc_info 的 首地址 ,变量的类型是 struct proc_info_list
arch/arm/kernel/asm-offsets.c DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));
r10+#PROCINFO_INITFUNC 的 值 是 变量 __v6_proc_info 中的 __cpu_flush 成员的地址
在arch/arm/mm/proc-v6.S中查找到 __v6_proc_info 的赋值, 该变量的__cpu_flush成员 为 b __v6_setup
综上:
1.该句就是调用了__v6_proc_info 的 __cpu_flush 成员 ,该成员为b __v6_setup
2.也就是说调用了 __v6_setup 函数
__v6_setup // arch/arm/mm/proc-v6.S
mov pc, lr // 通过将lr寄存器赋给pc,导致对__enable_mmu的调用
1: b __enable_mmu
__enable_mmu
__turn_mmu_on
__turn_mmu_on
mov r3, r13 // r13 中 为 __mmap_switched 的地址
mov pc, r3 // 将r13寄存器值赋给pc,调用__mmap_switched
__mmap_switched // arch/arm/kernel/head-common.S
b start_kernel // 调用在init/main.c文件中的 start_kernel
__HEAD
ENTRY(stext)
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
#ifndef CONFIG_XIP_KERNEL
adr r3, 2f
ldmia r3, {r4, r8}
sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
add r8, r8, r4 @ PHYS_OFFSET
#else
ldr r8, =PLAT_PHYS_OFFSET
#endif
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
bl __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
bl __fixup_pv_table
#endif
bl __create_page_tables
/*
* The following calls CPU specific code in a position independent
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
* xxx_proc_info structure selected by __lookup_processor_type
* above. On return, the CPU will be ready for the MMU to be
* turned on, and r0 will hold the CPU control register value.
*/
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
adr lr, BSYM(1f) @ return (PIC) address
mov r8, r4 @ set TTBR1 to swapper_pg_dir
ARM( add pc, r10, #PROCINFO_INITFUNC )
THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( mov pc, r12 )
1: b __enable_mmu
ENDPROC(stext)
版权声明:本文为u011011827原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。