Linux 启动流程之自解压(二)

Linux 启动流程之自解压(二)

2 Head.s .start段程序入口start

Start是zImage在启动时,最开始执行的代码。也就是说.start段被链接到代码的最开头处。

.section ".start", #alloc, #execinstr
		//创建.start段,将以下代码放入该段空间中
/*
 * sort out different calling conventions
 */
		.align
		/*
		 * Always enter in ARM state for CPUs that support the ARM ISA.
		 * As of today (2014) that's exactly the members of the A and R
		 * classes.
		 */
 AR_CLASS(	.arm	)
start:
		.type	start,#function
		.rept	7
		__nop
		.endr
#ifndef CONFIG_THUMB2_KERNEL
		mov	r0, r0
#else
 AR_CLASS(	sub	pc, pc, #3	)	@ A/R: switch to Thumb2 mode
  M_CLASS(	nop.w			)	@ M: already in Thumb2 mode
		.thumb
#endif
		W(b)	1f

		.word	_magic_sig	@ Magic numbers to help the loader
		.word	_magic_start	@ absolute load/run zImage address
		.word	_magic_end	@ zImage end address
		.word	0x04030201	@ endianness flag
		.word	0x45454545	@ another magic number to indicate
		.word	_magic_table	@ additional data table

		__EFI_HEADER
1:
 ARM_BE8(	setend	be		)	@ go BE8 if compiled for BE8,大小端获取
 AR_CLASS(	mrs	r9, cpsr	)		
#ifdef CONFIG_ARM_VIRT_EXT
		bl	__hyp_stub_install	@ get into SVC mode, reversibly
#endif
		mov	r7, r1			@ save architecture ID,保存arch_id到r7
		mov	r8, r2			@ save atags pointer,保存启动参数到r8

#ifndef CONFIG_CPU_V7M
		/*
		 * 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:
		safe_svcmode_maskall r0 @使CPU进去SVC模式
		msr	spsr_cxsf, r9		@ Save the CPU boot mode in
						@ SPSR
#endif

3 Head.s .text段

3.1 内核加压地址的确定

//TEXT_OFFSET是代码相对于物理内存的偏移,通常选为32k=0x8000。
//这个是有原因的,主要适用于存放Cache的一级页表。
//先看CONFIG_AUTO_ZRELADDR这个宏所含的内容,
//它的意思是如果你不知道ZRELADDR地址要定在内存什么地方,那么这段代码就可以帮你。
//看到0xf8000000了吧,那么后面有多少个0呢?
//答案是27个,那么2的27次方就是128M,这就明白了,
//只要你把解压程序放在你最后解压完成后的内核空间的128M之内的偏移的话,
//就可以自动设定好解压后内核要运行的地址ZRELADDR。

//如果你没有定义的话,那么,就会去取zreladdr作为最后解压的内核运行地。
//那么这个zreladdr是从哪里来的呢?
//答案是在:arch/arm/boot/compressed/Makefile中定义的

#ifdef CONFIG_AUTO_ZRELADDR
		/*
		 * Find the start of physical memory.  As we are executing
		 * without the MMU on, we are in the physical address space.
		 * We just need to get rid of any offset by aligning the
		 * address.
		 *
		 * This alignment is a balance between the requirements of
		 * different platforms - we have chosen 128MB to allow
		 * platforms which align the start of their physical memory
		 * to 128MB to use this feature, while allowing the zImage
		 * to be placed within the first 128MB of memory on other
		 * platforms.  Increasing the alignment means we place
		 * stricter alignment requirements on the start of physical
		 * memory, but relaxing it means that we break people who
		 * are already placing their zImage in (eg) the top 64MB
		 * of this range.
		 */
		mov	r4, pc
		and	r4, r4, #0xf8000000
		/* Determine final kernel image address. */
		add	r4, r4, #TEXT_OFFSET
#else
		ldr	r4, =zreladdr
#endif

3.2 Zreladdr的来源

# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
Endif

ZRELADDR的定义如下:
ifneq ($(MACHINE),)
include $(srctree)/$(MACHINE)/Makefile.boot
endif
# Note: the following conditions must always be true:

#   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)

#   PARAMS_PHYS must be within 4MB of ZRELADDR

#   INITRD_PHYS must be in RAM

ZRELADDR    := $(zreladdr-y)
PARAMS_PHYS:= $(params_phys-y)
INITRD_PHYS:= $(initrd_phys-y)

而里面的几个参数是在每个arch/arm/Mach-xxx/ Makefile.boot里面定义的,内容如下:
zreladdr-y := 0x20008000
params_phys-y := 0x20000100
initrd_phys-y := 0x21000000
这下知道了,绕了一大圈,终于知道r4存的是什么了,就是最后内核解压的起址,也是最后解压后的内核的运行地址,记住,这个地址很重要。
Linux基本参数,如下表:

在这里插入图片描述

发布了47 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/u013836909/article/details/104885861
今日推荐