内核编译过程
从顶层makefile查找以理关系如下
反过来就是编译顺序,下面是编译顺序以及生成结果。
1.顶层Makefile编译生成vmlinux
编译命令
cmd_vmlinux := arm-linux-ld -EL -p --no-undefined -X --build-id -o vmlinux -T
arch/arm/kernel/vmlinux.lds
arch/arm/kernel/head.o
arch/arm/kernel/init_task.o
init/built-in.o
--start-group
usr/built-in.o
arch/arm/vfp/built-in.o
arch/arm/kernel/built-in.o
arch/arm/mm/built-in.o
arch/arm/common/built-in.o
arch/arm/net/built-in.o
arch/arm/mach-s5p4418/built-in.o
arch/arm/plat-s5p4418/built-in.o
kernel/built-in.o mm/built-in.o
fs/built-in.o
ipc/built-in.o
security/built-in.o
crypto/built-in.o
block/built-in.o
arch/arm/lib/lib.a
lib/lib.a
arch/arm/lib/built-in.o
lib/built-in.o
drivers/built-in.o
sound/built-in.o
firmware/built-in.o
net/built-in.o
--end-group
.tmp_kallsyms2.o
2.arch/arm/boot/Makefile将vmlinux去除编译信息得到arch/arm/boot/Image
编译命令
cmd_arch/arm/boot/Image := arm-linux-objcopy -O binary -R .comment -S
vmlinux arch/arm/boot/Image
3.arch/arm/boot/compressed/Makefile将arch/arm/boot/Image进行gz压缩得到arch/arm/boot/compressed/piggy.gzip
编译命令
cmd_arch/arm/boot/compressed/piggy.gzip :=
(cat arch/arm/boot/compressed/../Image | gzip -n -f -9 >
arch/arm/boot/compressed/piggy.gzip) || (rm -f arch/arm/boot/compressed/piggy.gzip ; false)
4.arch/arm/boot/compressed/Makefile编译包含piggy.gzip的arch/arm/boot/compressed/piggy.gzip.S得到arch/arm/boot/compressed/piggy.gzip.o
5.arch/arm/boot/compressed/Makefile编译连接arch/arm/boot/compressed/piggy.gzip.o以及自解压程序得到arch/arm/boot/compressed/vmlinux
编译命令
cmd_arch/arm/boot/compressed/vmlinux :=
arm-linux-ld -EL
--defsym _kernel_bss_size=905184 --defsym
zreladdr=0x40008000 -p --no-undefined -X -T
arch/arm/boot/compressed/vmlinux.lds
arch/arm/boot/compressed/head.o
arch/arm/boot/compressed/piggy.gzip.o
arch/arm/boot/compressed/misc.o
arch/arm/boot/compressed/decompress.o
arch/arm/boot/compressed/string.o
arch/arm/boot/compressed/lib1funcs.o
arch/arm/boot/compressed/ashldi3.o
-o arch/arm/boot/compressed/vmlinux
6.arch/arm/boot/Makefile去除arm/boot/compressed/vmlinux的调试信息得到arch/arm/boot/zImage
编译命令
cmd_arch/arm/boot/zImage := arm-linux-objcopy -O binary -R .comment -S
arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage
整个生成图解
入口makefile
内核最后完成编译的文件夹一般是linux/arch/arm/boot/
编译完生成zImage
arch/arm/boot/Makefile
zImage是由compressed/vmlinux生成的
找到汇编入口
看一下连接脚本,通过连接脚本找到入口
linux/arch/arm/boot/compressed/Makefile
是vmlinux.lds.in ps:$(obj)的值就是当前目录。
linux/arch/arm/boot/compressed/vmlinux.lds.in
入口为_start,根据makefile可知入口在linux/arch/arm/boot/compressed/head.S
,head.S主要完成了内核的解压,然后跳到内核起始地址正式启动内核。
start:
.type start,#function
.rept 7
mov r0, r0
.endr
ARM( mov r0, r0 )
ARM( b 1f )
THUMB( adr r12, BSYM(1f) )
THUMB( bx r12 )
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
THUMB( .thumb )
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
#ifndef __ARM_ARCH_2__
/*
* Booting from Angel - need to enter SVC mode and disable
* FIQs/IRQs (numeric definitions from angel arm.h source).
* We only do this if we were in user mode on entry.
*/
mrs r2, cpsr @ get current mode
tst r2, #3 @ not user?
bne not_angel
mov r0, #0x17 @ angel_SWIreason_EnterSVC
ARM( swi 0x123456 ) @ angel_SWI_ARM
THUMB( svc 0xab ) @ angel_SWI_THUMB
not_angel:
mrs r2, cpsr @ turn off interrupts to
orr r2, r2, #0xc0 @ prevent angel from running
msr cpsr_c, r2
#else
teqp pc, #0x0c000003 @ turn off interrupts
#endif
.text
#ifdef CONFIG_AUTO_ZRELADDR
@ determine final kernel image address
mov r4, pc
and r4, r4, #0xf8000000
add r4, r4, #TEXT_OFFSET
#else
ldr r4, =zreladdr
#endif
bl cache_on
restart: adr r0, LC0
ldmia r0, {r1, r2, r3, r6, r10, r11, r12}
ldr sp, [r0, #28]
sub r0, r0, r1 @ calculate the delta offset
add r6, r6, r0 @ _edata
add r10, r10, r0 @ inflated kernel size location
ldrb r9, [r10, #0]
ldrb lr, [r10, #1]
orr r9, r9, lr, lsl #8
ldrb lr, [r10, #2]
ldrb r10, [r10, #3]
orr r9, r9, lr, lsl #16
orr r9, r9, r10, lsl #24
#ifndef CONFIG_ZBOOT_ROM
add sp, sp, r0
add r10, sp, #0x10000
#else
mov r10, r6
#endif
mov r5, #0 @ init dtb size to 0
#ifdef CONFIG_ARM_APPENDED_DTB
ldr lr, [r6, #0]
#ifndef __ARMEB__
ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian
#else
ldr r1, =0xd00dfeed
#endif
cmp lr, r1
bne dtb_check_done @ not found
#ifdef CONFIG_ARM_ATAG_DTB_COMPAT
add sp, sp, #0x10000
stmfd sp!, {r0-r3, ip, lr}
mov r0, r8
mov r1, r6
sub r2, sp, r6
bl atags_to_fdt
cmp r0, #1
sub r0, r4, #TEXT_OFFSET
add r0, r0, #0x100
mov r1, r6
sub r2, sp, r6
bleq atags_to_fdt
ldmfd sp!, {r0-r3, ip, lr}
sub sp, sp, #0x10000
#endif
mov r8, r6 @ use the appended device tree
ldr r5, =_kernel_bss_size
adr r1, wont_overwrite
sub r1, r6, r1
subs r1, r5, r1
addhi r9, r9, r1
ldr r5, [r6, #4]
#ifndef __ARMEB__
eor r1, r5, r5, ror #16
bic r1, r1, #0x00ff0000
mov r5, r5, ror #8
eor r5, r5, r1, lsr #8
#endif
add r5, r5, #7
bic r5, r5, #7
add r6, r6, r5
add r10, r10, r5
add sp, sp, r5
dtb_check_done:
#endif
add r10, r10, #16384
cmp r4, r10
bhs wont_overwrite
add r10, r4, r9
adr r9, wont_overwrite
cmp r10, r9
bls wont_overwrite
add r10, r10, #((reloc_code_end - restart + 256) & ~255)
bic r10, r10, #255
adr r5, restart
bic r5, r5, #31
sub r9, r6, r5 @ size to copy
add r9, r9, #31 @ rounded up to a multiple
bic r9, r9, #31 @ ... of 32 bytes
add r6, r9, r5
add r9, r9, r10
1: ldmdb r6!, {r0 - r3, r10 - r12, lr}
cmp r6, r5
stmdb r9!, {r0 - r3, r10 - r12, lr}
bhi 1b
sub r6, r9, r6
#ifndef CONFIG_ZBOOT_ROM
add sp, sp, r6
#endif
bl cache_clean_flush
adr r0, BSYM(restart)
add r0, r0, r6
mov pc, r0
wont_overwrite:
orrs r1, r0, r5
beq not_relocated
add r11, r11, r0
add r12, r12, r0
#ifndef CONFIG_ZBOOT_ROM
add r2, r2, r0
add r3, r3, r0
1: ldr r1, [r11, #0] @ relocate entries in the GOT
add r1, r1, r0 @ This fixes up C references
cmp r1, r2 @ if entry >= bss_start &&
cmphs r3, r1 @ bss_end > entry
addhi r1, r1, r5 @ entry += dtb size
str r1, [r11], #4 @ next entry
cmp r11, r12
blo 1b
add r2, r2, r5
add r3, r3, r5
#else
1: ldr r1, [r11, #0] @ relocate entries in the GOT
cmp r1, r2 @ entry < bss_start ||
cmphs r3, r1 @ _end < entry
addlo r1, r1, r0 @ table. This fixes up the
str r1, [r11], #4 @ C references.
cmp r11, r12
blo 1b
#endif
not_relocated: mov r0, #0
1: str r0, [r2], #4 @ clear bss
str r0, [r2], #4
str r0, [r2], #4
str r0, [r2], #4
cmp r2, r3
blo 1b
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
ARM( mov pc, r4 ) @ call kernel
THUMB( bx r4 ) @ entry point is always ARM
start:
预留中断向量表跳到紧接着后面的一个1:
1:
关中断,打开cache加速解压
restart:
检查设备树,准备数据段位置,也就是解压目的地,跳到wont_overwrite
wont_overwrite:
跳到not_relocated
not_relocated:
调用decompress_kernel解压内核,关闭cache,ARM( mov pc, r4 ) @ call kernel
进入内核
内核代码
linux/arch/arm/kernel/head.S
是内核真正的起始代码,主要完成硬件初始化,具体不详细分析,之后进入linux/arch/arm/kernel/head-common.S
。
linux/arch/arm/kernel/head-common.S
主要是__mmap_switched代码段,这时候已经开启了mmu,设置data、bss、stack和保存一下值就跳入C语言linux/init/main.c
的start_kernel了。
linux/init/main.c
的整个启动过程都围绕start_kernel和rest_init