Chinaunix首页 | 论坛 | 博客
  • 博客访问: 449236
  • 博文数量: 72
  • 博客积分: 3186
  • 博客等级: 中校
  • 技术积分: 1039
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-07 16:53
文章分类

全部博文(72)

文章存档

2012年(1)

2011年(5)

2010年(10)

2009年(56)

我的朋友

分类: LINUX

2011-07-17 13:03:20

关于
vmlinux -> arch/arm/boot/Image -> arch/arm/boot/compressed/vmlinux -> arm/arch/boot/zImage 
的生成过程,见 make uImage(uImage生成过程)

linux/arch/arm/boot/compressed/head.S

start:
/* 
* 从反汇编可以看到,开头有8句 NOP
*/
.type start,#function
.rept 7
mov r0, r0
.endr
   ARM( mov r0, r0 )
   ARM( b 1f )

/*
* Magic会被bootloader读取并判断是否是zImage
* start 和 _edata 是编译后确定的地址,由这两个值便可以确定编
* 译后的 Image 的长度,bootloader 可以根据这个长度来决定要复
* 制的内核映像大小。
*/
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
/*
* r1, r2 分别为 bootloader 传入的参数
*/
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer

/*
* 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.
* 确保此时 CPU 为 SVC 模式,如果不是则主动使用SWI指令来切换到
* SVC 模式(特权模式)
*/
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

{{{
上面这段反汇编如下:

00000000 :
       0: e1a00000 nop ; (mov r0, r0)
       4: e1a00000 nop ; (mov r0, r0)
       8: e1a00000 nop ; (mov r0, r0)
       c: e1a00000 nop ; (mov r0, r0)
      10: e1a00000 nop ; (mov r0, r0)
      14: e1a00000 nop ; (mov r0, r0)
      18: e1a00000 nop ; (mov r0, r0)
      1c: e1a00000 nop ; (mov r0, r0)
      20: ea000002 b 30 <_text+0x30>
      24: 016f2818 cmneq pc, r8, lsl r8 ;
      28: 00000000 andeq r0, r0, r0
      2c: 000b7d68 andeq r7, fp, r8, ror #26
      30: e1a07001 mov r7, r1
      34: e1a08002 mov r8, r2
      38: e10f2000 mrs r2, CPSR
      3c: e3120003 tst r2, #3
      40: 1a000001 bne 4c
      44: e3a00017 mov r0, #23
      48: ef123456 svc 0x00123456
}}}

not_angel:
/*
* 关闭中断
*/
mrs r2, cpsr @ turn off interrupts to
orr r2, r2, #0xc0 @ prevent angel from running
msr cpsr_c, r2
/*
* 见 arch/arm/Kconfig, zreladdr 是在 make menuconfig 是设定的
* 对于 smdk2410 它设置为 0x30008000
*/
ldr r4, =zreladdr
/*
* 打开数据和指定cache,见其注释。
* FIXME: 这里打开 cache 的目的?
*/
bl cache_on

/*
 * 这里用的是 adr,这个伪指令与 ldr 不同,adr是根据当前PC位置来获取某个内存值,
 * 利用它来编写位置无关代码。ldr则刚好相反,ldr 引用的地址在编译后就已确定
 */
restart: adr r0, LC0
ldmia r0, {r1, r2, r3, r5, r6, r9, r11, r12}
ldr sp, [r0, #32]

{{{
将 vmlinux load 到 SDRAM 的 0x30400000 处,经过上面的代码后,寄存器的值如下
System and User mode registers
      r0: 30400150       r1: 00000150       r2: 000b7d68       r3: 000b7d8c 
      r4: 30008000       r5: 00000000       r6: 000b7d68       r7: 0000000b 
      r8: 33f986e4       r9: 00174d04      r10: 40000000      r11: 000b7d34 
     r12: 000b7d5c   sp_usr: ffffffff   lr_usr: ffffffff       pc: 30400074 
    cpsr: 600000d3 

Supervisor mode shadow registers
  sp_svc: 000b8d8c   lr_svc: 304002b0 spsr_svc: f00000fb 
  
  下面几句是计算当前偏移地址。编译后,LC0 地址已经确定,见上面的 r1,
  即LC0标号编译后指定的地址是 0x00000150。
  而当前运行时,通过adr伪指令,根据当前PC偏移得到的LC0地址却是0x30400150,
  将这个地址值放到r0中。
}}}
/*
* We might be running at a different address.  We need
* to fix up various pointers.
*/
sub r0, r0, r1 @ calculate the delta offset
add r5, r5, r0 @ _start
add r6, r6, r0 @ _edata

/* malloc space is above the relocated stack (64k max) */
add sp, sp, r0
add r10, sp, #0x10000

链接后,sp在最后 bss 后预留了4k空间作为栈,再往高地址预留64k

.align 2
.type LC0, #object
LC0: .word LC0 @ r1
.word __bss_start @ r2
.word _end @ r3
.word _start @ r5
.word _edata @ r6
.word _image_size @ r9
.word _got_start @ r11
.word _got_end @ ip
.word user_stack_end @ sp
.size LC0, . - LC0
这里的代码目的就是要将压缩后的Image重新解压到指定地址上,所以在解压之前要保证当
前所在的地址空间范围与解压后的地址空间范围不会重叠。如果有重叠则要先处理重叠。
无重叠则直接跳到 wont_overwrite , 见下面代码。

cmp r4, r10
bhs wont_overwrite
add r10, r4, r9
cmp r10, r5
bls wont_overwrite
接下来就是校正GOT表中的地址了。如果地址偏移 r0 不移0, 则将 GOT 表中每个值都加上
偏移。
teq r0, #0
beq not_relocated
add r11, r11, r0
add r12, r12, r0

/*
* 校正BSS地址
*/
add r2, r2, r0
add r3, r3, r0

/*
* 校正GOT表的地址
*/
1: ldr r1, [r11, #0] @ relocate entries in the GOT
add r1, r1, r0 @ table.  This fixes up the
str r1, [r11], #4 @ C references.
cmp r11, r12
blo 1b
/*
* BSS 段清0
*/
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
mov pc, r4 @ call kernel
可以看到最后 pc 将跳到 r4 地址处,r4 的值从一开始就没变过,一直是 zreladdr

阅读(4015) | 评论(0) | 转发(0) |
0

上一篇:arm swi 软中断测试

下一篇:简单休眠

给主人留下些什么吧!~~