内核自解压代码注释

内核启动流程分析:
arch/arm/boot/compressed/head
.S 文件分析:正真启动内核前的工作
120行开始:
start函数定义
start:
.type start,#function@声明start为函数类型
.rept 8
mov r0, r0          @相当于八条空操作
.endr

b 1f
.word 0x016f2818@ Magic numbers to help the loader用于uboot确认kernel存在
.word start@ absolute load/run zImage address   由bootp.lds文件定义
.word _edata@ zImage end address
1: mov r7, r1 @ save architecture ID  此处r1和r2的值来自于uboot传递
mov r8, r2    @ save atags pointer

#ifndef __ARM_ARCH_2__       @因为没有定义ARM的第二个架构,所以要执行下面
/*
* 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 在进入svc管理模式(也就是保护模式)前拷贝当前状态寄存器
tst r2, #3@ not user?
                  @判断当前所处的模式是否为普通用户模式,因为只有user mode下cpsr低两位为0
                   @uboot进入kernel已经是svc32 mode,如果是从angle进入则是user mode
bne not_angel    @如果不是user mode跳到下面not_angel
mov r0, #0x17@ angel_SWIreason_EnterSVC 如果是user mode,软件中断设置成svc模式M[4:0]:10011:supervisor mode
swi 0x123456@ angel_SWI_ARM 为什么是0x123456,只要后面的的合法的24为立即数就可以
                   @执行时,程序进入SWI异常处理子程序SoftwareInterrupt,然后根据R0的内容跳转到相应的子分支,这里即进入svc模式
not_angel:
mrs r2, cpsr@ 拷贝当前状态寄存器
orr r2, r2, #0xc0@ 将屏蔽中断的值合并到r2中
msr cpsr_c, r2      @ turn off interrupts(IRQ & FIQ) to prevent angel from running
#else   @无用分支
teqp pc, #0x0c000003@ turn off interrupts
#endif

.text
adr r0, LC0    @保存标号LC0地址,LC0在后面定义,adr指令和当前程序运行的位置有关(连接地址都是0x0)


ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}  @此时r0指向LC0的开始地址,根据下面LC0的定义可知,r1将被赋予LC0的地址
subs r0, r0, r1@ calculate the delta offset  subs:影响cpsr的z位
                       @这里获得当前运行地址与链接地址的偏移量,存入r0中为0x30008000
                                @ if delta is zero, we are
beq not_relocated@ running at the address we were linked at.   r0=r1:跳转,not_relocata不重新定向加载

##############################################################################

@从nand启动时,由于内核已被搬移,标号LC0的地址不是以地址0为偏移的,
@这中间就存在一个固定的地址偏移,在s3c2440中是0x30008000
/*
* We're running at a different address.  We need to fix
* up various pointers:
*   r5 - zImage base address  是zImage的基地址
*   r6 - GOT start            是全局偏移表的开始地址
*   ip - GOT end
*
*   要重定向的情况
*/
add r5, r5, r0
add r6, r6, r0
add ip, ip, r0

#ifndef CONFIG_ZBOOT_ROM    @这个也没有定义,要执行下面的东东
/*
* If we're running fully PIC === CONFIG_ZBOOT_ROM = n,
* we need to fix up pointers into the BSS region.
*   r2 - BSS start
*   r3 - BSS end
*   sp - stack pointer
*/
add r2, r2, r0
add r3, r3, r0
add sp, sp, r0

/*
* Relocate all entries in the GOT table.
*/
1: ldr r1, [r6, #0] @ relocate entries in the GOT
add r1, r1, r0        @ table.  This fixes up the
str r1, [r6], #4@ C references.
cmp r6, ip
blo 1b
#else
/*
* Relocate entries in the GOT table.  We only relocate
* the entries that are outside the (relocated) BSS region.
*/
1: ldr r1, [r6, #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, [r6], #4@ C references.
cmp r6, ip
blo 1b
#endif
############################################################################
not_relocated: movr0, #0
1: str r0, [r2], #4 @ clear bss(Init BSS section) 看上面就明白
str r0, [r2], #4
str r0, [r2], #4
str r0, [r2], #4
cmp r2, r3
blo 1b                 @条件跳转:小于跳转

/*
* The C runtime environment should now be setup
* sufficiently.  Turn the cache on, set up some
* pointers, and start decompressing.
*设置进入c函数前的准备工作,打开cache,设置sp指针,开始进行解压
*/
bl cache_on       @这个标号在后面有定义,过程比较复杂,涉及的相关的流程如下:
                @cache_on --> b call_cache_fn --> 通过查表调用了 __armv4_cache_on --> b __setup_mmu

mov r1, sp   @ malloc space above stack 由于此时sp指向4k栈的顶端,注意是“顶端”,这个很关键
add r2, sp, #0x10000    @ 64k max:r2保存的是解压函数需要的缓冲内存的结束地址

/*
 * 检查是否会覆盖压缩内核映像本身
 * Check to see if we will overwrite ourselves.
 *   r4 = final kernel address
 *   r5 = start of this image
 *   r2 = end of malloc space (and therefore this image)
 * We basically want:
 *   r4 >= r2 -> OK
 *   r4 + image length <= r5 -> OK
 */
cmp r4, r2              @第一个判断
bhs wont_overwrite      @大于等于跳转
@r4为内核执行地址,此时为0X30008000,r2此时为用户栈定,即解压函数所需内存缓冲的开始处,
@显然r4 < r2所以不会跳转。

sub r3, sp, r5        @ > compressed kernel size压缩的内核文件大小
add r0, r4, r3, lsl #2@ allow for 4x expansion
cmp r0, r5              @第二个判断
bls wont_overwrite      @小于等于
        @r5是内核映像的开始地址0X30008000,r6为内核映像大小,r4为解压后内核开始地址,
        @此时为0X30008000,r5为解压前映存放的开始位置,此时也为0X30008000。下面的判
        @断是,看解压后的内核是不是会覆盖未解压的映像。显然是覆盖的,所以是不会跳转的。
        @注意:内核映像解压后不会超过解压前的4倍大小。
        @就是说nand启动到这里,执行完bls  wont_overwrite就完成了自引导过程。

mov r5, r2@ decompress after malloc space
mov r0, r5@r5做中介获得r2的一份拷贝
mov r3, r7
bl decompress_kernel   @调用解压内核c函数 :需要4个参数
                       @函数原型decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,int arch_id)
                       @r0->output_start:指解压后内核输出的起始位置
                       @r1->free_mem_ptr_p:解压缓冲区起始地址
                       @r2->free_mem_ptr_end_p:解压缓冲区结束地址
                       @r3->arch_id:机器ID
        @调用完解压函数,它的返回值“kernel size”放在r0中
add r0, r0, #127 + 128@ alignment + stack
bic r0, r0, #127@ align the kernel length
/*
 * r0     = decompressed kernel length
 * r1-r3  = unused
 * r4     = kernel execution address
 * r5     = decompressed kernel start
 * r6     = processor ID
 * r7     = architecture ID
 * r8     = atags pointer
 * r9-r14 = corrupted
 */
add r1, r5, r0@ end of decompressed kernel
adr r2, reloc_start
ldr r3, LC1
add r3, r2, r3
1: ldmia r2!, {r9 - r14} @ copy relocation code
stmia r1!, {r9 - r14}
ldmia r2!, {r9 - r14}
stmia r1!, {r9 - r14}
cmp r2, r3
blo 1b
add sp, r1, #128@ relocate the stack

bl cache_clean_flush
add pc, r5, r0@ call relocation code

/*
 * We're not in danger of overwriting ourselves.  Do this the simple way.
 *
 * r4     = kernel execution address
 * r7     = architecture ID
 */
@不会覆盖时调用
wont_overwrite: movr0, r4
mov r3, r7
bl decompress_kernel
b call_kernel

.type LC0, #object      @定义一个数据对象,类似于C语言中的结构体
LC0: .word LC0  @ r1
.word __bss_start @ r2
.word _end @ r3
.word zreladdr    @ r4 zImage的运行地址0x30008000
.word _start @ r5 压缩内核映像的起始地址0x30008000
.word _got_start @ r6
.word _got_end @ ip
.word user_stack+4096 @ sp
LC1: .word reloc_end - reloc_start
.size LC0, . - LC0

/*
 * All code following this line is relocatable.  It is relocated by
 * the above code to the end of the decompressed kernel image and
 * executed there.  During this time, we have no stacks.
 *
 * r0     = decompressed kernel length
 * r1-r3  = unused
 * r4     = kernel execution address
 * r5     = decompressed kernel start
 * r6     = processor ID
 * r7     = architecture ID
 * r8     = atags pointer
 * r9-r14 = corrupted
 */

@由reloc_start至reloc_end的代码复制解压后的内核代码到0x30008000处,并调用call_kernel跳转到0x30008000处执行
reloc_start: addr9, r5, r0
sub r9, r9, #128@ do not copy the stack
debug_reloc_start
mov r1, r4
1:
.rept 4
ldmia r5!, {r0, r2, r3, r10 - r14}@ relocate kernel
stmia r1!, {r0, r2, r3, r10 - r14}
.endr

cmp r5, r9
blo 1b
add sp, r1, #128@ relocate the stack
debug_reloc_end

call_kernel: blcache_clean_flush
bl cache_off
mov r0, #0@ must be zero
mov r1, r7@ restore architecture number
mov r2, r8@ restore atags pointer

movpc, r4 @ call kernel前面已经说明:r4是真正内核的开始执行的地址


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值