20.Linux3.4內核啓動源碼分析(zImage內核解壓過程分析)

內核編譯過程

從頂層makefile查找以理關係如下

Created with Raphaël 2.2.0arch/arm/boot/Makefile(zImage)arch/arm/boot/compressed/Makefile(compressed/vmlinux)arch/arm/boot/compressed/Makefile(piggy.gzip.o)arch/arm/boot/compressed/Makefile(piggy.gzip)arch/arm/boot/Makefile(Image)Makefile(vmlinux)

反過來就是編譯順序,下面是編譯順序以及生成結果。

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
整個生成圖解
objcopy
gz
objcopy
vmlinux
arch/arm/boot/Image
compressed/piggy.gzip
piggy.gzip.o
compressed/piggy.gzip.S
compressed/vmlinux
head.S
misc.c
decompress.c
lib1funcs.c
ashldi3.c
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章